home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / mail / pine3.96.tar.gz / pine3.96.tar / pine3.96 / pine / other.c < prev    next >
C/C++ Source or Header  |  1996-07-10  |  169KB  |  6,352 lines

  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: other.c,v 4.242 1996/07/10 23:05:37 mikes Exp $";
  3. #endif
  4. /*----------------------------------------------------------------------
  5.  
  6.             T H E    P I N E    M A I L   S Y S T E M
  7.  
  8.    Laurence Lundblade and Mike Seibel
  9.    Networks and Distributed Computing
  10.    Computing and Communications
  11.    University of Washington
  12.    Administration Builiding, AG-44
  13.    Seattle, Washington, 98195, USA
  14.    Internet: lgl@CAC.Washington.EDU
  15.              mikes@CAC.Washington.EDU
  16.  
  17.    Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  18.  
  19.  
  20.    Pine and Pico are registered trademarks of the University of Washington.
  21.    No commercial use of these trademarks may be made without prior written
  22.    permission of the University of Washington.
  23.  
  24.    Pine, Pico, and Pilot software and its included text are Copyright
  25.    1989-1996 by the University of Washington.
  26.  
  27.    The full text of our legal notices is contained in the file called
  28.    CPYRIGHT, included with this distribution.
  29.  
  30.  
  31.    Pine is in part based on The Elm Mail System:
  32.     ***********************************************************************
  33.     *  The Elm Mail System  -  Revision: 2.13                             *
  34.     *                                                                     *
  35.     *             Copyright (c) 1986, 1987 Dave Taylor              *
  36.     *             Copyright (c) 1988, 1989 USENET Community Trust   *
  37.     ***********************************************************************
  38.  
  39.  
  40.   ----------------------------------------------------------------------*/
  41.  
  42. /*======================================================================
  43.       other.c
  44.  
  45.       This implements the "setup" screen of miscellaneous commands such
  46.   as keyboard lock, and disk usage
  47.  
  48.   ====*/
  49.  
  50. #include "headers.h"
  51.  
  52. #define    BODY_LINES(X)    ((X)->ttyo->screen_rows -HEADER_ROWS(X)-FOOTER_ROWS(X))
  53.  
  54. #define    CONFIG_SCREEN_TITLE        "SETUP CONFIGURATION"
  55. #define    CONFIG_SCREEN_HELP_TITLE    "HELP FOR SETUP CONFIGURATION"
  56. #define    R_SELD                '*'
  57. #define    EXIT_PMT "Commit changes (\"Yes\" replaces settings, \"No\" abandons changes)"
  58. static char *empty_val  = "Empty Value";
  59. static char *empty_val2 = "<Empty Value>";
  60. #define EMPTY_VAL_LEN     11
  61. static char *no_val     = "No Value Set";
  62. #define NO_VAL_LEN        12
  63. static char *fixed_val  = "Value is Fixed";
  64.  
  65.  
  66. typedef struct conf_line {
  67.     char         *varname,            /* alloc'd var name string   */
  68.              *value;            /* alloc'd var value string  */
  69.     short          varoffset;        /* offset from screen left   */
  70.     short          valoffset;        /* offset from screen left   */
  71.     struct variable   *var;            /* pointer to pinerc var     */
  72.     short          varmem;            /* value's index, if list    */
  73.     int              (*tool)();        /* tool to manipulate values */
  74.     struct key_menu  *keymenu;            /* tool-specific  keymenu    */
  75.     HelpType          help;            /* variable's help text      */
  76.     unsigned          flags;
  77.     void         *scrap;
  78.     struct conf_line *varnamep;        /* pointer to varname        */
  79.     struct conf_line *headingp;        /* pointer to heading        */
  80.     struct conf_line *next, *prev;
  81. } CONF_S;
  82.  
  83. /*
  84.  * Valid for flags argument of config screen tools or flags field in CONF_S
  85.  */
  86. #define    CF_CHANGES    0x01    /* Have been earlier changes */
  87. #define    CF_NOSELECT    0x02    /* This line is unselectable */
  88. #define    CF_NOHILITE    0x04    /* Don't highlight varname   */
  89. #define    CF_NUMBER    0x08    /* Input should be numeric   */
  90. #define    CF_INVISIBLEVAR    0x10    /* Don't show the varname    */
  91.  
  92. typedef struct save_config {
  93.     union {
  94.     char  *p;
  95.     char **l;
  96.     bitmap_t features;
  97.     } user_val;
  98. } SAVED_CONFIG_S;
  99.  
  100. /*
  101.  *
  102.  */
  103. typedef struct conf_screen {
  104.     CONF_S  *current,
  105.         *prev,
  106.         *top_line,
  107.         *first_line;
  108. } OPT_SCREEN_S;
  109.  
  110. typedef enum {Config, PrintConfig, NoPrint} ConfigType;
  111.  
  112.  
  113. static OPT_SCREEN_S *opt_screen;
  114. static char **def_printer_line;
  115. #if defined(DOS) || defined(OS2)
  116. static char *config_colors[] = {"black", "blue", "green", "cyan", "red",
  117.                 "magenta", "yellow", "white", NULL};
  118. #endif
  119. static char no_ff[] = "-no-formfeed";
  120.  
  121. #define next_confline(p)  ((p) ? (p)->next : NULL)
  122. #define prev_confline(p)  ((p) ? (p)->prev : NULL)
  123.  
  124. /*
  125.  * Internal prototypes
  126.  */
  127. void     draw_klocked_body PROTO((char *, char *));
  128. void     update_option_screen PROTO((struct pine *, OPT_SCREEN_S *, Pos *));
  129. void     print_option_screen PROTO((OPT_SCREEN_S *, char *));
  130. void     option_screen_redrawer PROTO(());
  131. int     conf_scroll_screen PROTO((struct pine *,CONF_S *,char *,ConfigType));
  132. HelpType config_help PROTO((int, int));
  133. int      text_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  134. int     checkbox_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  135. int     flag_checkbox_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  136. int     radiobutton_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  137. int     yesno_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  138. int     print_select_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  139. int     print_edit_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  140. void     set_def_printer_value PROTO((char *));
  141. int     gripe_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  142. void     toggle_feature_bit PROTO((struct pine *, int, struct variable *,
  143.                     char *));
  144. void     config_add_list PROTO((struct pine *, CONF_S **, char **,
  145.                 char ***, int));
  146. void     config_del_list_item PROTO((CONF_S **, char ***));
  147. char    *pretty_value PROTO((struct pine *, CONF_S *));
  148. int      offer_to_fix_pinerc PROTO((struct pine *));
  149. CONF_S    *new_confline PROTO((CONF_S **));
  150. void     free_confline PROTO((CONF_S **));
  151. CONF_S    *first_confline PROTO((CONF_S *));
  152. CONF_S  *first_sel_confline PROTO((CONF_S *));
  153. CONF_S    *last_confline PROTO((CONF_S *));
  154. int      flag_exit_cmd PROTO((unsigned));
  155. int      config_exit_cmd PROTO((unsigned));
  156. int     screen_exit_cmd PROTO((unsigned, char *));
  157. int     config_scroll_up PROTO((long));
  158. int     config_scroll_down PROTO((long));
  159. int     config_scroll_to_pos PROTO((long));
  160. CONF_S  *config_top_scroll PROTO((struct pine *, CONF_S *));
  161. char    *printer_name PROTO ((char *));
  162. #ifdef    _WINDOWS
  163. int     config_scroll_callback PROTO((int, long));
  164. #endif
  165. void     fix_side_effects PROTO ((struct pine *, struct variable *, int));
  166. SAVED_CONFIG_S *save_config_vars PROTO((struct pine *));
  167. void            revert_to_saved_config PROTO((struct pine *, SAVED_CONFIG_S *));
  168. void            free_saved_config PROTO((struct pine *, SAVED_CONFIG_S **));
  169. void     att_cur_drawer PROTO((void));
  170. char    *sigedit_exit_for_pico PROTO(());
  171. int     exclude_config_var PROTO((struct pine *, struct variable *));
  172.  
  173.  
  174. static char *klockin, *klockame;
  175.  
  176. void
  177. redraw_kl_body()
  178. {
  179. #ifndef NO_KEYBOARD_LOCK
  180.     ClearScreen();
  181.  
  182.     set_titlebar("KEYBOARD LOCK", ps_global->mail_stream,
  183.          ps_global->context_current, ps_global->cur_folder, NULL,
  184.          1, FolderName, 0, 0);
  185.  
  186.     PutLine0(6,3 ,
  187.        "You may lock this keyboard so that no one else can access your mail");
  188.     PutLine0(8, 3 ,
  189.        "while you are away.  The screen will be locked after entering the ");
  190.     PutLine0(10, 3 ,
  191.        "password to be used for unlocking the keyboard when you return.");
  192.     fflush(stdout);
  193. #endif
  194. }
  195.  
  196.  
  197. void
  198. redraw_klocked_body()
  199. {
  200. #ifndef NO_KEYBOARD_LOCK
  201.     ClearScreen();
  202.  
  203.     set_titlebar("KEYBOARD LOCK", ps_global->mail_stream,
  204.          ps_global->context_current, ps_global->cur_folder, NULL,
  205.          1, FolderName, 0, 0);
  206.  
  207.     PutLine2(6, 3, "This keyboard is locked by %s <%s>.",klockame, klockin);
  208.     PutLine0(8, 3, "To unlock, enter password used to lock the keyboard.");
  209.     fflush(stdout);
  210. #endif
  211. }
  212.  
  213.  
  214. #ifndef NO_KEYBOARD_LOCK
  215. /*----------------------------------------------------------------------
  216.           Execute the lock keyboard command
  217.  
  218.     Args: None
  219.  
  220.   Result: keyboard is locked until user gives password
  221.   ---*/
  222.  
  223. lock_keyboard()
  224. {
  225.     struct pine *ps = ps_global;
  226.     char inpasswd[80], passwd[80], pw[80];
  227.     HelpType help = NO_HELP;
  228.     SigType (*hold_quit)();
  229.     int i, times, old_suspend;
  230.  
  231.     passwd[0] = '\0';
  232.     redraw_kl_body();
  233.     ps->redrawer = redraw_kl_body;
  234.  
  235.     times = atoi(ps->VAR_KBLOCK_PASSWD_COUNT);
  236.     if(times < 1 || times > 5){
  237.     dprint(2, (debugfile,
  238.     "Kblock-passwd-count var out of range (1 to 5) [%d]\n", times));
  239.     times = 1;
  240.     }
  241.  
  242.     inpasswd[0] = '\0';
  243.  
  244.     for(i = 0; i < times; i++){
  245.     pw[0] = '\0';
  246.     while(1){            /* input pasword to use for locking */
  247.         int rc;
  248.         char prompt[50];
  249.  
  250.         sprintf(prompt,
  251.         "%s password to LOCK keyboard %s: ",
  252.         i ? "Retype" : "Enter",
  253.         i > 1 ? "(Yes, again) " : "");
  254.  
  255.         rc =  optionally_enter(pw, -FOOTER_ROWS(ps), 0, 30, 0, 1,
  256.                     prompt, NULL, help, 0);
  257.  
  258.         if(rc == 3)
  259.           help = help == NO_HELP ? h_kb_lock : NO_HELP;
  260.         else if(rc == 1 || pw[0] == '\0'){
  261.         q_status_message(SM_ORDER, 0, 2, "Keyboard lock cancelled");
  262.         return(-1);
  263.         }
  264.         else if(rc != 4)
  265.           break;
  266.     }
  267.  
  268.     if(!inpasswd[0])
  269.       strcpy(inpasswd, pw);
  270.     else if(strcmp(inpasswd, pw)){
  271.         q_status_message(SM_ORDER, 0, 2,
  272.         "Mismatch with initial password: keyboard lock cancelled");
  273.         return(-1);
  274.     }
  275.     }
  276.  
  277.     if(want_to("Really lock keyboard with entered password", 'y', 'n',
  278.            NO_HELP, 0, 0) != 'y'){
  279.     q_status_message(SM_ORDER, 0, 2, "Keyboard lock cancelled");
  280.     return(-1);
  281.     }
  282.  
  283.     draw_klocked_body(ps->VAR_USER_ID ? ps->VAR_USER_ID : "<no-user>",
  284.           ps->VAR_PERSONAL_NAME ? ps->VAR_PERSONAL_NAME : "<no-name>");
  285.  
  286.     ps->redrawer = redraw_klocked_body;
  287.     if(old_suspend = F_ON(F_CAN_SUSPEND, ps_global))
  288.       F_TURN_OFF(F_CAN_SUSPEND, ps_global);
  289.  
  290.     while(strcmp(inpasswd, passwd)){
  291.     if(passwd[0])
  292.       q_status_message(SM_ORDER | SM_DING, 3, 3,
  293.              "Password to UNLOCK doesn't match password used to LOCK");
  294.         
  295.         help = NO_HELP;
  296.         while(1){
  297.         int rc;
  298.         rc =  optionally_enter(passwd, -FOOTER_ROWS(ps), 0, 30, 0, 1, 
  299.                    "Enter password to UNLOCK keyboard : ",NULL,
  300.                    help, OE_DISALLOW_CANCEL);
  301.         if(rc == 3) {
  302.         help = help == NO_HELP ? h_oe_keylock : NO_HELP;
  303.         continue;
  304.         }
  305.  
  306.         if(rc != 4)
  307.           break;
  308.         }
  309.     }
  310.  
  311.     if(old_suspend)
  312.       F_TURN_ON(F_CAN_SUSPEND, ps_global);
  313.  
  314.     q_status_message(SM_ORDER, 0, 3, "Keyboard Unlocked");
  315.     return(0);
  316. }
  317.  
  318.  
  319. void
  320. draw_klocked_body(login, username)
  321.     char *login, *username;
  322. {
  323.     klockin = login;
  324.     klockame = username;
  325.     redraw_klocked_body();
  326. }
  327. #endif /* !NO_KEYBOARD_LOCK */
  328.  
  329.  
  330.  
  331. /*----------------------------------------------------------------------
  332.     Serve up the current signature within pico for editing
  333.  
  334.     Args: file to edit
  335.  
  336.   Result: signature changed or not.
  337.   ---*/
  338. void
  339. signature_edit(sigfile)
  340.     char *sigfile;
  341. {
  342.     int         editor_result;
  343.     char     sig_path[MAXPATH+1], *errstr = NULL;
  344.     STORE_S *msgso, *tmpso = NULL;
  345.     gf_io_t  gc, pc;
  346.     PICO     pbuf;
  347.  
  348.     if(!signature_path(sigfile, sig_path, MAXPATH)){
  349.         q_status_message(SM_ORDER, 3, 4, "No signature file defined.");
  350.     return;
  351.     }
  352.  
  353.     memset(&pbuf, 0, sizeof(PICO));
  354.  
  355.     pbuf.raw_io        = Raw;
  356.     pbuf.showmsg       = display_message_for_pico;
  357.     pbuf.newmail       = new_mail_for_pico;
  358.     pbuf.ckptdir       = checkpoint_dir_for_pico;
  359.     pbuf.exittest      = sigedit_exit_for_pico;
  360.     pbuf.upload           = (ps_global->VAR_UPLOAD_CMD
  361.               && ps_global->VAR_UPLOAD_CMD[0])
  362.                ? upload_msg_to_pico : NULL;
  363.     pbuf.keybinit      = init_keyboard;
  364.     pbuf.helper        = helper;
  365.     pbuf.resize           = resize_for_pico;
  366.     pbuf.alt_ed        = (ps_global->VAR_EDITOR && ps_global->VAR_EDITOR[0])
  367.                  ? ps_global->VAR_EDITOR : NULL;
  368.     pbuf.alt_spell     = ps_global->VAR_SPELLER;
  369.     pbuf.fillcolumn    = ps_global->composer_fillcol;
  370.     pbuf.menu_rows     = FOOTER_ROWS(ps_global) - 1;
  371.     pbuf.composer_help = h_composer_sigedit;
  372.     pbuf.ins_help      = h_composer_ins;
  373.     pbuf.search_help   = h_composer_search;
  374.     pbuf.browse_help   = h_composer_browse;
  375.  
  376.     pbuf.pine_anchor   = set_titlebar("SIGNATURE EDITOR",
  377.                       ps_global->mail_stream,
  378.                       ps_global->context_current,
  379.                       ps_global->cur_folder,
  380.                       ps_global->msgmap,
  381.                       0, FolderName, 0, 0);
  382.     pbuf.pine_version  = pine_version;
  383.     pbuf.pine_flags    = 0;
  384.     pbuf.pine_flags   |= F_ON(F_CAN_SUSPEND,ps_global)        ? P_SUSPEND : 0;
  385.     pbuf.pine_flags   |= F_ON(F_USE_FK,ps_global)        ? P_FKEYS : 0;
  386.     pbuf.pine_flags   |= ps_global->restricted            ? P_SECURE : 0;
  387.     pbuf.pine_flags   |= (F_ON(F_ENABLE_ALT_ED,ps_global) ||
  388.               F_ON(F_ALT_ED_NOW,ps_global) ||
  389.               (ps_global->VAR_EDITOR
  390.                   && ps_global->VAR_EDITOR[0])) ? P_ADVANCED : 0;
  391.     pbuf.pine_flags   |= F_ON(F_ALT_ED_NOW,ps_global)        ? P_ALTNOW : 0;
  392.     pbuf.pine_flags   |= F_ON(F_USE_CURRENT_DIR,ps_global)  ? P_CURDIR : 0;
  393.     pbuf.pine_flags   |= F_ON(F_SUSPEND_SPAWNS,ps_global)   ? P_SUBSHELL : 0;
  394.     pbuf.pine_flags   |= F_ON(F_COMPOSE_MAPS_DEL,ps_global) ? P_DELRUBS : 0;
  395.     pbuf.pine_flags   |= F_ON(F_ENABLE_TAB_COMPLETE,ps_global)
  396.                                 ? P_COMPLETE : 0;
  397.  
  398.     pbuf.pine_flags   |= F_ON(F_SHOW_CURSOR, ps_global)     ? P_SHOCUR : 0;
  399.     pbuf.pine_flags   |= F_ON(F_DEL_FROM_DOT, ps_global)    ? P_DOTKILL : 0;
  400.     pbuf.pine_flags   |= (!ps_global->VAR_CHAR_SET
  401.               || !strucmp(ps_global->VAR_CHAR_SET, "US-ASCII"))
  402.               ? P_HIBITIGN: 0;
  403.     pbuf.pine_flags   |= F_ON(F_ENABLE_DOT_FILES, ps_global)? P_DOTFILES : 0;
  404.     if(ps_global->VAR_OPER_DIR){
  405.     pbuf.oper_dir    = ps_global->VAR_OPER_DIR;
  406.     pbuf.pine_flags |= P_TREE;
  407.     }
  408.  
  409.     /* NOTE: at this point, alot of pico struct fields are null'd out
  410.      * thanks to the leading memset; in particular "headents" which tells
  411.      * pico to behave like a normal editor (though modified slightly to
  412.      * let the caller dictate the file to edit and such)...
  413.      */
  414.  
  415.     /*
  416.      * Now alloc and init the text to pass pico
  417.      */
  418.     if(!(msgso = so_get(PicoText, NULL, EDIT_ACCESS))){
  419.         q_status_message(SM_ORDER | SM_DING, 3, 4,
  420.              "Error allocating space for signature file");
  421.     dprint(1, (debugfile, "Can't alloc space for signature_edit"));
  422.     return;
  423.     }
  424.     else
  425.       pbuf.msgtext = so_text(msgso);
  426.  
  427.     if(can_access(sig_path, READ_ACCESS) == 0
  428.        && !(tmpso = so_get(FileStar, sig_path, READ_ACCESS))){
  429.     char *problem = error_description(errno);
  430.     q_status_message2(SM_ORDER | SM_DING, 3, 3, "Error editing %s: %s",
  431.               sig_path, problem ? problem : "<NULL>");
  432.     dprint(1, (debugfile, "signature_edit: can't open %s: %s", sig_path,
  433.            problem ? problem : "<NULL>"));
  434.     return;
  435.     }
  436.     else if(tmpso){            /* else, fill pico's edit buffer */
  437.     gf_set_so_readc(&gc, tmpso);    /* read from file, write pico buf */
  438.     gf_set_so_writec(&pc, msgso);
  439.     gf_filter_init();        /* no filters needed */
  440.     if(errstr = gf_pipe(gc, pc)){
  441.         q_status_message1(SM_ORDER | SM_DING, 3, 5,
  442.                   "Error reading signature \"%s\"", errstr);
  443.     }
  444.  
  445.     so_give(&tmpso);
  446.     }
  447.  
  448.     if(!errstr){
  449. #ifdef _WINDOWS
  450.     mswin_setwindowmenu (MENU_COMPOSER);
  451. #endif
  452.  
  453.     /*------ OK, Go edit the signature ------*/
  454.     editor_result = pico(&pbuf);
  455.  
  456. #ifdef _WINDOWS
  457.     mswin_setwindowmenu (MENU_DEFAULT);
  458. #endif
  459.     if(editor_result & COMP_GOTHUP){
  460.         hup_signal();        /* do what's normal for a hup */
  461.     }
  462.     else{
  463.         fix_windsize(ps_global);
  464.         init_signals();
  465.     }
  466.  
  467.     if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){
  468.     }
  469.     else{
  470.             /*------ Must have an edited buffer, write it to .sig -----*/
  471.         unlink(sig_path);        /* blast old copy */
  472.         if(tmpso = so_get(FileStar, sig_path, WRITE_ACCESS)){
  473.         so_seek(msgso, 0L, 0);
  474.         gf_set_so_readc(&gc, msgso);    /* read from pico buf */
  475.         gf_set_so_writec(&pc, tmpso);    /* write sig file */
  476.         gf_filter_init();        /* no filters needed */
  477.         if(errstr = gf_pipe(gc, pc)){
  478.             q_status_message1(SM_ORDER | SM_DING, 3, 5,
  479.                       "Error writing signature \"%s\"",
  480.                       errstr);
  481.         }
  482.  
  483.         so_give(&tmpso);
  484.         }
  485.         else{
  486.         q_status_message1(SM_ORDER | SM_DING, 3, 3,
  487.                   "Error writing %s", sig_path);
  488.         dprint(1, (debugfile, "signature_edit: can't write %s",
  489.                sig_path));
  490.         }
  491.     }
  492.     }
  493.  
  494.     so_give(&msgso);
  495. }
  496.  
  497.  
  498.  
  499. /*
  500.  *
  501.  */
  502. char *
  503. sigedit_exit_for_pico()
  504. {
  505.     int          rv;
  506.     char     *rstr = NULL;
  507.     void    (*redraw)() = ps_global->redrawer;
  508.     static ESCKEY_S opts[] = {
  509.     {'y', 'y', "Y", "Yes"},
  510.     {'n', 'n', "N", "No"},
  511.     {-1, 0, NULL, NULL}
  512.     };
  513.  
  514.     ps_global->redrawer = NULL;
  515.     fix_windsize(ps_global);
  516.  
  517.     while(1){
  518.     rv = radio_buttons("Exit editor and apply changes? ",
  519.                -FOOTER_ROWS(ps_global), opts,
  520.                'y', 'x', NO_HELP, RB_NORM);
  521.     if(rv == 'y'){                /* user ACCEPTS! */
  522.         break;
  523.     }
  524.     else if(rv == 'n'){            /* Declined! */
  525.         rstr = "No Changes Saved";
  526.         break;
  527.     }
  528.     else if(rv == 'x'){            /* Cancelled! */
  529.         rstr = "Exit Cancelled";
  530.         break;
  531.     }
  532.     }
  533.  
  534.     ps_global->redrawer = redraw;
  535.     return(rstr);
  536. }
  537.  
  538.  
  539.  
  540. /*
  541.  *  * * * * *    Start of Config Screen Support Code   * * * * * 
  542.  */
  543.  
  544. static struct key config_text_keys[] = 
  545.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  546.     {"E","Exit Config",KS_EXITMODE},{"C","[Change Val]",KS_NONE},
  547.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  548.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  549.     {"A","Add Value",KS_NONE},    {"D","Delete Val",KS_NONE},
  550.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  551. INST_KEY_MENU(config_text_keymenu, config_text_keys);
  552.  
  553. static struct key config_checkbox_keys[] = 
  554.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  555.     {"E","Exit Config",KS_EXITMODE},{"X","[Set/Unset]",KS_NONE},
  556.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  557.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  558.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  559.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  560. INST_KEY_MENU(config_checkbox_keymenu, config_checkbox_keys);
  561.  
  562. static struct key config_radiobutton_keys[] = 
  563.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  564.     {"E","Exit Config",KS_EXITMODE},{"*","[Select]",KS_NONE},
  565.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  566.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  567.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  568.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  569. INST_KEY_MENU(config_radiobutton_keymenu, config_radiobutton_keys);
  570.  
  571. static struct key config_yesno_keys[] = 
  572.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  573.     {"E","Exit Config",KS_EXITMODE},{"C","[Change]",KS_NONE},
  574.     {"P","Prev", KS_NONE},        {"N","Next", KS_NONE},
  575.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  576.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  577.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  578. INST_KEY_MENU(config_yesno_keymenu, config_yesno_keys);
  579.  
  580. /*
  581.  * Test to indicate what should be saved in case user wants to abandon
  582.  * changes
  583.  */
  584. #define    SAVE_INCLUDE(P,V) (!exclude_config_var((P), (V))          \
  585.             || ((V)->is_user && (V)->is_used && !(V)->is_obsolete \
  586.               && ((V) == &(P)->vars[V_PERSONAL_PRINT_COMMAND])))
  587.  
  588. /*
  589.  * Test to return if the given feature should be included
  590.  * in the config screen.
  591.  */
  592. /* First, standard exclusions... */
  593. #define    F_STD_EX(F)    ((F) == F_OLD_GROWTH            \
  594.              || (F) == F_DISABLE_CONFIG_SCREEN    \
  595.              || (F) == F_DISABLE_PASSWORD_CMD    \
  596.              || (F) == F_DISABLE_KBLOCK_CMD        \
  597.              || (F) == F_DISABLE_SIGEDIT_CMD    \
  598.              || (F) == F_DISABLE_UPDATE_CMD        \
  599.              || (F) == F_DISABLE_DFLT_IN_BUG_RPT    \
  600.              || (F) == F_DISABLE_ALARM        \
  601.              || (F) == F_AGG_SEQ_COPY)
  602.  
  603. /* Then, os-dependent/feature-relative exclusions... */
  604. #if    defined(DOS) || defined(OS2)
  605. #define    F_SPEC_EX(F)    ((F) == F_BACKGROUND_POST)
  606. #else
  607. #ifdef    MOUSE
  608. #define    MOUSE_EX(F)    (0)
  609. #else
  610. #define    MOUSE_EX(F)    ((F) == F_ENABLE_MOUSE)
  611. #endif    /* MOUSE */
  612.  
  613. #ifdef    BACKGROUND_POST
  614. #define    BG_EX(F)    (0)
  615. #else
  616. #define    BG_EX(F)    ((F) == F_BACKGROUND_POST)
  617. #endif
  618.  
  619.  
  620. #define    F_SPEC_EX(F)    ((F) == F_USE_FK || MOUSE_EX(F) || BG_EX(F))
  621. #endif
  622.  
  623.  
  624. #define    F_INCLUDE(F)    (!(F_STD_EX(F) || F_SPEC_EX(F)))
  625.  
  626.  
  627.  
  628. /*----------------------------------------------------------------------
  629.     Present pinerc data for manipulation
  630.  
  631.     Args: None
  632.  
  633.   Result: help edit certain pinerc fields.
  634.   ---*/
  635. void
  636. option_screen(ps)
  637.     struct pine *ps;
  638. {
  639.     char      tmp[MAXPATH+1];
  640.     int          i, j, ln = 0, lv;
  641.     struct      variable  *vtmp;
  642.     CONF_S     *ctmpa = NULL, *ctmpb, *first_line = NULL;
  643.     NAMEVAL_S     *f;
  644.     SAVED_CONFIG_S *vsave;
  645.  
  646.     mailcap_free(); /* free resources we won't be using for a while */
  647.  
  648.     if(ps->fix_fixed_warning){
  649.     set_titlebar(CONFIG_SCREEN_TITLE, ps->mail_stream,
  650.              ps->context_current,
  651.              ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0);
  652.         if(offer_to_fix_pinerc(ps))
  653.           write_pinerc(ps);
  654.     }
  655.  
  656.     /*
  657.      * First, find longest variable name
  658.      */
  659.     for(vtmp = ps->vars; vtmp->name; vtmp++){
  660.     if(exclude_config_var(ps, vtmp))
  661.       continue;
  662.  
  663.     if((i = strlen(vtmp->name)) > ln)
  664.       ln = i;
  665.     }
  666.  
  667.     /*
  668.      * Next, allocate and initialize config line list...
  669.      */
  670.     for(vtmp = ps->vars; vtmp->name; vtmp++){
  671.     if(exclude_config_var(ps, vtmp))
  672.       continue;
  673.  
  674.     new_confline(&ctmpa)->var = vtmp;
  675.     if(!first_line)
  676.       first_line = ctmpa;
  677.  
  678.     ctmpa->valoffset = ln + 3;
  679.     ctmpa->keymenu     = &config_text_keymenu;
  680.     ctmpa->help     = config_help(vtmp - ps->vars, 0);
  681.     ctmpa->tool     = text_tool;
  682.  
  683.     sprintf(tmp, "%-*s =", ln, vtmp->name);
  684.     ctmpa->varname  = cpystr(tmp);
  685.     ctmpa->varnamep = ctmpb = ctmpa;
  686.     if(vtmp == &ps->vars[V_FEATURE_LIST]){    /* special checkbox case */
  687.         ctmpa->flags       |= CF_NOSELECT;
  688.         ctmpa->keymenu      = &config_checkbox_keymenu;
  689.         ctmpa->tool        = NULL;
  690.  
  691.         /* put a nice delimiter before list */
  692.         new_confline(&ctmpa)->var = NULL;
  693.         ctmpa->varnamep          = ctmpb;
  694.         ctmpa->keymenu          = &config_checkbox_keymenu;
  695.         ctmpa->help              = NO_HELP;
  696.         ctmpa->tool              = checkbox_tool;
  697.         ctmpa->valoffset          = 12;
  698.         ctmpa->flags             |= CF_NOSELECT;
  699.         ctmpa->value = cpystr("Set        Feature Name");
  700.  
  701.         new_confline(&ctmpa)->var = NULL;
  702.         ctmpa->varnamep          = ctmpb;
  703.         ctmpa->keymenu          = &config_checkbox_keymenu;
  704.         ctmpa->help              = NO_HELP;
  705.         ctmpa->tool              = checkbox_tool;
  706.         ctmpa->valoffset          = 12;
  707.         ctmpa->flags             |= CF_NOSELECT;
  708.         ctmpa->value = cpystr("---   ----------------------");
  709.  
  710.         /* find longest value's name */
  711.         for(lv = 0, i = 0; f = feature_list(i); i++)
  712.           if(F_INCLUDE(f->value))
  713.         if(lv < (j = strlen(f->name)))
  714.           lv = j;
  715.         
  716.         for(i = 0; f = feature_list(i); i++){
  717.         if(F_INCLUDE(f->value)){
  718.             new_confline(&ctmpa)->var = vtmp;
  719.             ctmpa->varnamep          = ctmpb;
  720.             ctmpa->keymenu          = &config_checkbox_keymenu;
  721.             ctmpa->help              = config_help(vtmp-ps->vars,
  722.                                 f->value);
  723.             ctmpa->tool              = checkbox_tool;
  724.             ctmpa->valoffset          = 12;
  725.             ctmpa->varmem          = i;
  726.             sprintf(tmp, "[%c]  %-*.*s",
  727.                 F_ON(f->value, ps) ? 'X' : ' ', lv, lv, f->name);
  728.             ctmpa->value = cpystr(tmp);
  729.         }
  730.         }
  731.     }
  732.     else if(vtmp == &ps->vars[V_SAVED_MSG_NAME_RULE]){ /* radio case */
  733.         ctmpa->flags       |= CF_NOSELECT;
  734.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  735.         ctmpa->tool        = NULL;
  736.  
  737.         /* put a nice delimiter before list */
  738.         new_confline(&ctmpa)->var = NULL;
  739.         ctmpa->varnamep          = ctmpb;
  740.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  741.         ctmpa->help              = NO_HELP;
  742.         ctmpa->tool              = radiobutton_tool;
  743.         ctmpa->valoffset          = 12;
  744.         ctmpa->flags             |= CF_NOSELECT;
  745.         ctmpa->value = cpystr("Set       Rule Values");
  746.  
  747.         new_confline(&ctmpa)->var = NULL;
  748.         ctmpa->varnamep          = ctmpb;
  749.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  750.         ctmpa->help              = NO_HELP;
  751.         ctmpa->tool              = radiobutton_tool;
  752.         ctmpa->valoffset          = 12;
  753.         ctmpa->flags             |= CF_NOSELECT;
  754.         ctmpa->value = cpystr("---   ----------------------");
  755.  
  756.         /* find longest value's name */
  757.         for(lv = 0, i = 0; f = save_msg_rules(i); i++)
  758.           if(lv < (j = strlen(f->name)))
  759.         lv = j;
  760.         
  761.         for(i = 0; f = save_msg_rules(i); i++){
  762.         new_confline(&ctmpa)->var = vtmp;
  763.         ctmpa->varnamep          = ctmpb;
  764.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  765.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  766.         ctmpa->tool          = radiobutton_tool;
  767.         ctmpa->valoffset      = 12;
  768.         ctmpa->varmem          = i;
  769.         sprintf(tmp, "(%c)  %-*.*s",
  770.             (ps->save_msg_rule == f->value) ? R_SELD : ' ',
  771.             lv, lv, f->name);
  772.         ctmpa->value = cpystr(tmp);
  773.         }
  774.     }
  775.     else if(vtmp == &ps->vars[V_FCC_RULE]){        /* radio case */
  776.         ctmpa->flags       |= CF_NOSELECT;
  777.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  778.         ctmpa->tool        = NULL;
  779.  
  780.         /* put a nice delimiter before list */
  781.         new_confline(&ctmpa)->var = NULL;
  782.         ctmpa->varnamep          = ctmpb;
  783.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  784.         ctmpa->help              = NO_HELP;
  785.         ctmpa->tool              = radiobutton_tool;
  786.         ctmpa->valoffset          = 12;
  787.         ctmpa->flags             |= CF_NOSELECT;
  788.         ctmpa->value = cpystr("Set       Rule Values");
  789.  
  790.         new_confline(&ctmpa)->var = NULL;
  791.         ctmpa->varnamep          = ctmpb;
  792.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  793.         ctmpa->help              = NO_HELP;
  794.         ctmpa->tool              = radiobutton_tool;
  795.         ctmpa->valoffset          = 12;
  796.         ctmpa->flags             |= CF_NOSELECT;
  797.         ctmpa->value = cpystr("---   ----------------------");
  798.  
  799.         /* find longest value's name */
  800.         for(lv = 0, i = 0; f = fcc_rules(i); i++)
  801.           if(lv < (j = strlen(f->name)))
  802.         lv = j;
  803.         
  804.         for(i = 0; f = fcc_rules(i); i++){
  805.         new_confline(&ctmpa)->var = vtmp;
  806.         ctmpa->varnamep          = ctmpb;
  807.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  808.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  809.         ctmpa->tool          = radiobutton_tool;
  810.         ctmpa->valoffset      = 12;
  811.         ctmpa->varmem          = i;
  812.         sprintf(tmp, "(%c)  %-*.*s",
  813.             (ps->fcc_rule == f->value) ? R_SELD : ' ',
  814.             lv, lv, f->name);
  815.         ctmpa->value = cpystr(tmp);
  816.         }
  817.     }
  818.     else if(vtmp == &ps->vars[V_SORT_KEY]){ /* radio case */
  819.         ctmpa->flags       |= CF_NOSELECT;
  820.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  821.         ctmpa->tool        = NULL;
  822.  
  823.         /* put a nice delimiter before list */
  824.         new_confline(&ctmpa)->var = NULL;
  825.         ctmpa->varnamep          = ctmpb;
  826.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  827.         ctmpa->help              = NO_HELP;
  828.         ctmpa->tool              = radiobutton_tool;
  829.         ctmpa->valoffset          = 12;
  830.         ctmpa->flags             |= CF_NOSELECT;
  831.         ctmpa->value = cpystr("Set       Sort Options");
  832.  
  833.         new_confline(&ctmpa)->var = NULL;
  834.         ctmpa->varnamep          = ctmpb;
  835.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  836.         ctmpa->help              = NO_HELP;
  837.         ctmpa->tool              = radiobutton_tool;
  838.         ctmpa->valoffset          = 12;
  839.         ctmpa->flags             |= CF_NOSELECT;
  840.         ctmpa->value = cpystr("---   ----------------------");
  841.  
  842.         /* find longest value's name */
  843.         for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
  844.           if(lv < (j = strlen(sort_name(i))))
  845.         lv = j;
  846.         
  847.         for(j = 0; j < 2; j++){
  848.         for(i = 0; ps->sort_types[i] != EndofList; i++){
  849.             new_confline(&ctmpa)->var = vtmp;
  850.             ctmpa->varnamep  = ctmpb;
  851.             ctmpa->keymenu   = &config_radiobutton_keymenu;
  852.             ctmpa->help         = config_help(vtmp - ps->vars, 0);
  853.             ctmpa->tool         = radiobutton_tool;
  854.             ctmpa->valoffset = 12;
  855.  
  856.             /*
  857.              * varmem == sort_type index (reverse doubles index)
  858.              */
  859.             ctmpa->varmem = i + (j * EndofList);
  860.             sprintf(tmp, "(%c)  %s%-*s%*s",
  861.                 (ps->def_sort == (SortOrder) i
  862.                           && ps->def_sort_rev == j)
  863.                   ? R_SELD : ' ',
  864.                 (j) ? "Reverse " : "",
  865.                 lv, sort_name(i),
  866.                 (j) ? 0 : 8, "");
  867.             ctmpa->value = cpystr(tmp);
  868.         }
  869.         }
  870.     }
  871.     else if(vtmp == &ps->vars[V_AB_SORT_RULE]){    /* radio case */
  872.         ctmpa->flags       |= CF_NOSELECT;
  873.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  874.         ctmpa->tool        = NULL;
  875.  
  876.         /* put a nice delimiter before list */
  877.         new_confline(&ctmpa)->var = NULL;
  878.         ctmpa->varnamep          = ctmpb;
  879.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  880.         ctmpa->help              = NO_HELP;
  881.         ctmpa->tool              = radiobutton_tool;
  882.         ctmpa->valoffset          = 12;
  883.         ctmpa->flags             |= CF_NOSELECT;
  884.         ctmpa->value = cpystr("Set       Rule Values");
  885.  
  886.         new_confline(&ctmpa)->var = NULL;
  887.         ctmpa->varnamep          = ctmpb;
  888.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  889.         ctmpa->help              = NO_HELP;
  890.         ctmpa->tool              = radiobutton_tool;
  891.         ctmpa->valoffset          = 12;
  892.         ctmpa->flags             |= CF_NOSELECT;
  893.         ctmpa->value = cpystr("---   ----------------------");
  894.  
  895.         /* find longest value's name */
  896.         for(lv = 0, i = 0; f = ab_sort_rules(i); i++)
  897.           if(lv < (j = strlen(f->name)))
  898.         lv = j;
  899.         
  900.         for(i = 0; f = ab_sort_rules(i); i++){
  901.         new_confline(&ctmpa)->var = vtmp;
  902.         ctmpa->varnamep          = ctmpb;
  903.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  904.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  905.         ctmpa->tool          = radiobutton_tool;
  906.         ctmpa->valoffset      = 12;
  907.         ctmpa->varmem          = i;
  908.         sprintf(tmp, "(%c)  %-*.*s",
  909.             (ps->ab_sort_rule == f->value) ? R_SELD : ' ',
  910.             lv, lv, f->name);
  911.         ctmpa->value = cpystr(tmp);
  912.         }
  913.     }
  914.     else if(vtmp == &ps->vars[V_GOTO_DEFAULT_RULE]){ /* radio case */
  915.         ctmpa->flags       |= CF_NOSELECT;
  916.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  917.         ctmpa->tool        = NULL;
  918.  
  919.         /* put a nice delimiter before list */
  920.         new_confline(&ctmpa)->var = NULL;
  921.         ctmpa->varnamep          = ctmpb;
  922.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  923.         ctmpa->help              = NO_HELP;
  924.         ctmpa->tool              = radiobutton_tool;
  925.         ctmpa->valoffset          = 12;
  926.         ctmpa->flags             |= CF_NOSELECT;
  927.         ctmpa->value = cpystr("Set       Rule Values");
  928.  
  929.         new_confline(&ctmpa)->var = NULL;
  930.         ctmpa->varnamep          = ctmpb;
  931.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  932.         ctmpa->help              = NO_HELP;
  933.         ctmpa->tool              = radiobutton_tool;
  934.         ctmpa->valoffset          = 12;
  935.         ctmpa->flags             |= CF_NOSELECT;
  936.         ctmpa->value = cpystr("---   ----------------------");
  937.  
  938.         /* find longest value's name */
  939.         for(lv = 0, i = 0; f = goto_rules(i); i++)
  940.           if(lv < (j = strlen(f->name)))
  941.         lv = j;
  942.         
  943.         for(i = 0; f = goto_rules(i); i++){
  944.         new_confline(&ctmpa)->var = vtmp;
  945.         ctmpa->varnamep          = ctmpb;
  946.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  947.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  948.         ctmpa->tool          = radiobutton_tool;
  949.         ctmpa->valoffset      = 12;
  950.         ctmpa->varmem          = i;
  951.         sprintf(tmp, "(%c)  %-*.*s",
  952.             (ps->goto_default_rule == f->value) ? R_SELD : ' ',
  953.             lv, lv, f->name);
  954.         ctmpa->value = cpystr(tmp);
  955.         }
  956.     }
  957. #if defined(DOS) || defined(OS2)
  958.     else if(vtmp == &ps->vars[V_NORM_FORE_COLOR] /* radio case */
  959.         || vtmp == &ps->vars[V_NORM_BACK_COLOR]
  960.         || vtmp == &ps->vars[V_REV_FORE_COLOR]
  961.         || vtmp == &ps->vars[V_REV_BACK_COLOR]){
  962.         ctmpa->flags       |= CF_NOSELECT;
  963.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  964.         ctmpa->tool        = NULL;
  965.  
  966.         /* put a nice delimiter before list */
  967.         new_confline(&ctmpa)->var = NULL;
  968.         ctmpa->varnamep          = ctmpb;
  969.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  970.         ctmpa->help              = NO_HELP;
  971.         ctmpa->tool              = radiobutton_tool;
  972.         ctmpa->valoffset          = 12;
  973.         ctmpa->flags             |= CF_NOSELECT;
  974.         ctmpa->value = cpystr("Set       Color Options");
  975.  
  976.         new_confline(&ctmpa)->var = NULL;
  977.         ctmpa->varnamep          = ctmpb;
  978.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  979.         ctmpa->help              = NO_HELP;
  980.         ctmpa->tool              = radiobutton_tool;
  981.         ctmpa->valoffset          = 12;
  982.         ctmpa->flags             |= CF_NOSELECT;
  983.         ctmpa->value = cpystr("---   ----------------------");
  984.  
  985.         /* find longest value's name */
  986.         for(lv = 0, i = 0; config_colors[i]; i++)
  987.           if(lv < (j = strlen(config_colors[i])))
  988.         lv = j;
  989.         
  990.         for(i = 0; config_colors[i]; i++){
  991.         new_confline(&ctmpa)->var = vtmp;
  992.         ctmpa->varnamep          = ctmpb;
  993.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  994.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  995.         ctmpa->tool          = radiobutton_tool;
  996.         ctmpa->valoffset      = 12;
  997.  
  998.         /*
  999.          * varmem == sort_type index (reverse doubles index)
  1000.          */
  1001.         ctmpa->varmem = i;
  1002.         sprintf(tmp, "(%c)  %-*.*s",
  1003.             !strucmp(ps->vars[vtmp - ps->vars].current_val.p,
  1004.                  config_colors[i]) ? R_SELD : ' ',
  1005.             lv, lv, config_colors[i]);
  1006.         ctmpa->value = cpystr(tmp);
  1007.         }
  1008.     }
  1009. #endif
  1010.     else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */
  1011.         ctmpa->keymenu = &config_yesno_keymenu;
  1012.         ctmpa->tool       = yesno_tool;
  1013.         if(vtmp->user_val.p && !strucmp(vtmp->user_val.p, "yes")
  1014.            || (!vtmp->user_val.p && vtmp->current_val.p
  1015.            && !strucmp(vtmp->current_val.p, "yes")))
  1016.           sprintf(tmp, "Yes%*s", ps->ttyo->screen_cols - ln - 3, "");
  1017.         else
  1018.           sprintf(tmp, "No%*s", ps->ttyo->screen_cols - ln - 2, "");
  1019.  
  1020.         ctmpa->value = cpystr(tmp);
  1021.     }
  1022.     else if(vtmp->is_list){
  1023.         if(vtmp->user_val.l){
  1024.         for(i = 0; vtmp->user_val.l[i]; i++){
  1025.             if(i)
  1026.               (void)new_confline(&ctmpa);
  1027.  
  1028.             ctmpa->var       = vtmp;
  1029.             ctmpa->varmem    = i;
  1030.             ctmpa->valoffset = ln + 3;
  1031.             ctmpa->value     = pretty_value(ps, ctmpa);
  1032.             ctmpa->keymenu   = &config_text_keymenu;
  1033.             ctmpa->help      = config_help(vtmp - ps->vars, 0);
  1034.             ctmpa->tool      = text_tool;
  1035.             ctmpa->varnamep  = ctmpb;
  1036.         }
  1037.         }
  1038.         else{
  1039.         ctmpa->varmem = 0;
  1040.         ctmpa->value  = pretty_value(ps, ctmpa);
  1041.         }
  1042.     }
  1043.     else{
  1044.         if(vtmp == &ps->vars[V_FILLCOL]
  1045.            || vtmp == &ps->vars[V_OVERLAP]
  1046.            || vtmp == &ps->vars[V_MARGIN]
  1047.            || vtmp == &ps->vars[V_STATUS_MSG_DELAY]
  1048.            || vtmp == &ps->vars[V_MAILCHECK])
  1049.           ctmpa->flags |= CF_NUMBER;
  1050.  
  1051.         ctmpa->value = pretty_value(ps, ctmpa);
  1052.     }
  1053.     }
  1054.  
  1055.     vsave = save_config_vars(ps);
  1056.     first_line = first_sel_confline(first_line);
  1057.     switch(conf_scroll_screen(ps, first_line, CONFIG_SCREEN_TITLE, Config)){
  1058.       case 0:
  1059.     break;
  1060.  
  1061.       case 1:
  1062.     write_pinerc(ps);
  1063.     break;
  1064.     
  1065.       case 10:
  1066.     revert_to_saved_config(ps, vsave);
  1067.     break;
  1068.       
  1069.       default:
  1070.     q_status_message(SM_ORDER,7,10,
  1071.         "conf_scroll_screen bad ret, not supposed to happen");
  1072.     break;
  1073.     }
  1074.  
  1075.     if(vsave[V_SORT_KEY].user_val.p && ps->vars[V_SORT_KEY].user_val.p
  1076.        && strcmp(vsave[V_SORT_KEY].user_val.p,
  1077.          ps->vars[V_SORT_KEY].user_val.p)){
  1078.     clear_index_cache();
  1079.     sort_current_folder(0, SortArrival, 0);
  1080.     }
  1081.  
  1082.     free_saved_config(ps, &vsave);
  1083. #ifdef _WINDOWS
  1084.     mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
  1085. #endif
  1086. }
  1087.  
  1088.  
  1089. /*
  1090.  * test whether or not a var is 
  1091.  *
  1092.  * returns:  1 if it should be excluded, 0 otw
  1093.  */
  1094. int
  1095. exclude_config_var(ps, var)
  1096.     struct pine *ps;
  1097.     struct variable *var;
  1098. {
  1099.     switch(var - ps->vars){
  1100.       case V_MAIL_DIRECTORY :
  1101.       case V_INCOMING_FOLDERS :
  1102.       case V_PRINTER :
  1103.       case V_PERSONAL_PRINT_COMMAND :
  1104.       case V_PERSONAL_PRINT_CATEGORY :
  1105.       case V_STANDARD_PRINTER :
  1106.       case V_LAST_TIME_PRUNE_QUESTION :
  1107.       case V_LAST_VERS_USED :
  1108.       case V_OPER_DIR :
  1109.       case V_TCPOPENTIMEO :
  1110.       case V_RSHOPENTIMEO :
  1111.       case V_SENDMAIL_PATH :
  1112.       case V_NEW_VER_QUELL :
  1113. #if defined(DOS) || defined(OS2)
  1114.       case V_UPLOAD_CMD :
  1115.       case V_UPLOAD_CMD_PREFIX :
  1116.       case V_DOWNLOAD_CMD :
  1117.       case V_DOWNLOAD_CMD_PREFIX :
  1118. #ifdef    _WINDOWS
  1119.       case V_FONT_NAME :
  1120.       case V_FONT_SIZE :
  1121.       case V_FONT_STYLE :
  1122.       case V_PRINT_FONT_NAME :
  1123.       case V_PRINT_FONT_SIZE :
  1124.       case V_PRINT_FONT_STYLE :
  1125.       case V_WINDOW_POSITION :
  1126. #endif    /* _WINDOWS */
  1127. #endif    /* DOS */
  1128.     return(1);
  1129.  
  1130.       default:
  1131.     break;
  1132.     }
  1133.  
  1134.     return(!(var->is_user && var->is_used && !var->is_obsolete));
  1135. }
  1136.  
  1137.  
  1138. #ifndef    DOS
  1139. static struct key printer_edit_keys[] = 
  1140.        {{"?","Help",KS_SCREENHELP},    {"Y","prYnt",KS_PRINT},
  1141.     {"E","Exit Config",KS_EXITMODE},{"S","[Select]",KS_NONE},
  1142.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  1143.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  1144.     {"A","Add Printer",KS_NONE},    {"D","DeletePrint",KS_NONE},
  1145.     {"C","Change",KS_SELECT},    {"W","WhereIs",KS_WHEREIS}};
  1146. INST_KEY_MENU(printer_edit_keymenu, printer_edit_keys);
  1147.  
  1148. static struct key printer_select_keys[] = 
  1149.        {{"?","Help",KS_SCREENHELP},    {"Y","prYnt",KS_PRINT},
  1150.     {"E","Exit Config",KS_EXITMODE},{"S","[Select]",KS_NONE},
  1151.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  1152.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  1153.     {NULL,NULL,KS_NONE},            {NULL,NULL,KS_NONE},
  1154.     {NULL,NULL,KS_NONE},            {"W","WhereIs",KS_WHEREIS}};
  1155. INST_KEY_MENU(printer_select_keymenu, printer_select_keys);
  1156.  
  1157. /*
  1158.  * Information used to paint and maintain a line on the configuration screen
  1159.  */
  1160. /*----------------------------------------------------------------------
  1161.     The printer selection screen
  1162.  
  1163.    Draws the screen and prompts for the printer number and the custom
  1164.    command if so selected.
  1165.  
  1166.  ----*/
  1167. void
  1168. select_printer(ps) 
  1169.     struct pine *ps;
  1170. {
  1171.     struct        variable  *vtmp;
  1172.     CONF_S       *ctmpa = NULL, *ctmpb = NULL, *heading = NULL,
  1173.          *start_line = NULL;
  1174.     int j, i, saved_printer_cat;
  1175.     char tmp[MAXPATH+1];
  1176.     SAVED_CONFIG_S *vsave;
  1177.     char *saved_printer, *p;
  1178.     char *nick, *cmd;
  1179.  
  1180.     if(ps_global->vars[V_PRINTER].is_fixed){
  1181.     q_status_message(SM_ORDER,3,5,
  1182.         "Sys. Mgmt. does not allow changing printer");
  1183.     return;
  1184.     }
  1185.  
  1186.     saved_printer = cpystr(ps->VAR_PRINTER);
  1187.     saved_printer_cat = ps->printer_category;
  1188.  
  1189.     new_confline(&ctmpa);
  1190.     ctmpa->valoffset = 2;
  1191.     ctmpa->keymenu   = &printer_select_keymenu;
  1192.     ctmpa->help      = NO_HELP;
  1193.     ctmpa->tool      = print_select_tool;
  1194.     ctmpa->flags    |= CF_NOSELECT;
  1195.     ctmpa->value
  1196. #ifdef OS2
  1197.       = cpystr("\"Select\" a port or |pipe-command as your default printer.");
  1198. #else
  1199.       = cpystr("You may \"Select\" a print command as your default printer.");
  1200. #endif
  1201.  
  1202.     new_confline(&ctmpa);
  1203.     ctmpa->valoffset = 2;
  1204.     ctmpa->keymenu   = &printer_select_keymenu;
  1205.     ctmpa->help      = NO_HELP;
  1206.     ctmpa->tool      = print_select_tool;
  1207.     ctmpa->flags    |= CF_NOSELECT;
  1208.     ctmpa->value
  1209. #ifdef OS2
  1210.       = cpystr("You may also add alternative ports or !pipes to the list in the \"Personally\"");
  1211. #else
  1212.       = cpystr("You may also add custom print commands to the list in the \"Personally\"");
  1213. #endif
  1214.  
  1215.     new_confline(&ctmpa);
  1216.     ctmpa->valoffset = 2;
  1217.     ctmpa->keymenu   = &printer_select_keymenu;
  1218.     ctmpa->help      = NO_HELP;
  1219.     ctmpa->tool      = print_select_tool;
  1220.     ctmpa->flags    |= CF_NOSELECT;
  1221.     ctmpa->value
  1222. #ifdef OS2
  1223.       = cpystr("selected port or |pipe\" section below.");
  1224. #else
  1225.       = cpystr("selected print command\" section below.");
  1226. #endif
  1227.  
  1228.     new_confline(&ctmpa);
  1229.     ctmpa->valoffset = 2;
  1230.     ctmpa->keymenu   = &printer_select_keymenu;
  1231.     ctmpa->help      = NO_HELP;
  1232.     ctmpa->tool      = print_select_tool;
  1233.     ctmpa->flags    |= CF_NOSELECT;
  1234.     ctmpa->value
  1235.       = cpystr("");
  1236.  
  1237.     new_confline(&ctmpa);
  1238.     ctmpa->valoffset = 4;
  1239.     ctmpa->keymenu   = &printer_select_keymenu;
  1240.     ctmpa->help      = NO_HELP;
  1241.     ctmpa->tool      = print_select_tool;
  1242.     ctmpa->flags    |= CF_NOSELECT;
  1243.     def_printer_line = &ctmpa->value;
  1244.     set_def_printer_value(ps->VAR_PRINTER);
  1245.  
  1246.     new_confline(&ctmpa);
  1247.     ctmpa->valoffset = 2;
  1248.     ctmpa->keymenu   = &printer_select_keymenu;
  1249.     ctmpa->help      = NO_HELP;
  1250.     ctmpa->tool      = print_select_tool;
  1251.     ctmpa->flags    |= CF_NOSELECT;
  1252.     ctmpa->value
  1253.       = cpystr("");
  1254.  
  1255. #ifndef OS2
  1256.     new_confline(&ctmpa);
  1257.     heading = ctmpa;
  1258.     ctmpa->keymenu   = &printer_select_keymenu;
  1259.     ctmpa->help      = NO_HELP;
  1260.     ctmpa->tool      = print_select_tool;
  1261.     ctmpa->varname
  1262.     = cpystr(" Printer attached to IBM PC or compatible, Macintosh");
  1263.     ctmpa->flags    |= CF_NOSELECT;
  1264.     ctmpa->value     = cpystr("");
  1265.     ctmpa->headingp  = heading;
  1266.  
  1267.     new_confline(&ctmpa);
  1268.     ctmpa->valoffset = 6;
  1269.     ctmpa->keymenu   = &printer_select_keymenu;
  1270.     ctmpa->help      = NO_HELP;
  1271.     ctmpa->tool      = print_select_tool;
  1272.     ctmpa->flags    |= CF_NOSELECT;
  1273.     ctmpa->value
  1274.       = cpystr("This may not work with all attached printers, and will depend on the");
  1275.     ctmpa->headingp  = heading;
  1276.  
  1277.     new_confline(&ctmpa);
  1278.     ctmpa->valoffset = 6;
  1279.     ctmpa->keymenu   = &printer_select_keymenu;
  1280.     ctmpa->help      = NO_HELP;
  1281.     ctmpa->tool      = print_select_tool;
  1282.     ctmpa->flags    |= CF_NOSELECT;
  1283.     ctmpa->value
  1284.       = cpystr("terminal emulation/communications software in use. It is known to work");
  1285.     ctmpa->headingp  = heading;
  1286.  
  1287.     new_confline(&ctmpa);
  1288.     ctmpa->valoffset = 6;
  1289.     ctmpa->keymenu   = &printer_select_keymenu;
  1290.     ctmpa->help      = NO_HELP;
  1291.     ctmpa->tool      = print_select_tool;
  1292.     ctmpa->flags    |= CF_NOSELECT;
  1293.     ctmpa->value
  1294.       = cpystr("with Kermit and the latest UW version of NCSA telnet on Macs and PCs,");
  1295.     ctmpa->headingp  = heading;
  1296.  
  1297.     new_confline(&ctmpa);
  1298.     ctmpa->valoffset = 6;
  1299.     ctmpa->keymenu   = &printer_select_keymenu;
  1300.     ctmpa->help      = NO_HELP;
  1301.     ctmpa->tool      = print_select_tool;
  1302.     ctmpa->flags    |= CF_NOSELECT;
  1303.     ctmpa->value
  1304.       = cpystr("Versaterm Pro on Macs, and WRQ Reflections on PCs.");
  1305.     ctmpa->headingp  = heading;
  1306.  
  1307.     new_confline(&ctmpa);
  1308.     start_line = ctmpb = ctmpa; /* default start line */
  1309.     ctmpa->valoffset = 17;
  1310.     ctmpa->keymenu   = &printer_select_keymenu;
  1311.     ctmpa->help      = h_config_set_att_ansi;
  1312.     ctmpa->tool      = print_select_tool;
  1313.     ctmpa->flags    |= CF_NOHILITE;
  1314.     ctmpa->varoffset = 8;
  1315.     ctmpa->varname   = cpystr("Printer:");
  1316.     ctmpa->value
  1317.       = cpystr(ANSI_PRINTER);
  1318.     ctmpa->varnamep  = ctmpb;
  1319.     ctmpa->headingp  = heading;
  1320.  
  1321.     new_confline(&ctmpa);
  1322.     ctmpa->valoffset = 17;
  1323.     ctmpa->keymenu   = &printer_select_keymenu;
  1324.     ctmpa->help      = h_config_set_att_ansi2;
  1325.     ctmpa->tool      = print_select_tool;
  1326.     ctmpa->flags    |= CF_NOHILITE;
  1327.     ctmpa->varoffset = 8;
  1328.     ctmpa->value     = (char *)fs_get(strlen(ANSI_PRINTER)+strlen(no_ff)+1);
  1329.     ctmpa->varnamep  = ctmpb;
  1330.     ctmpa->headingp  = heading;
  1331.     strcat(strcpy(ctmpa->value, ANSI_PRINTER), no_ff);
  1332. #endif
  1333.  
  1334.     new_confline(&ctmpa);
  1335.     ctmpa->valoffset = 0;
  1336.     ctmpa->keymenu   = &printer_select_keymenu;
  1337.     ctmpa->help      = NO_HELP;
  1338.     ctmpa->tool      = print_select_tool;
  1339.     ctmpa->flags    |= CF_NOSELECT;
  1340.     ctmpa->value = cpystr("");
  1341.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1342.  
  1343.  
  1344.     new_confline(&ctmpa);
  1345.     heading = ctmpa;
  1346.     ctmpa->valoffset = 6;
  1347.     ctmpa->keymenu   = &printer_select_keymenu;
  1348.     ctmpa->help      = NO_HELP;
  1349.     ctmpa->tool      = print_select_tool;
  1350.     ctmpa->varname
  1351. #ifdef OS2
  1352.         = cpystr(" Standard OS/2 printer port");
  1353. #else
  1354.     = cpystr(" Standard UNIX print command");
  1355. #endif
  1356.     ctmpa->value = cpystr("");
  1357.     ctmpa->flags    |= CF_NOSELECT;
  1358.     ctmpa->headingp  = heading;
  1359.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1360.  
  1361.     new_confline(&ctmpa);
  1362.     ctmpa->valoffset = 6;
  1363.     ctmpa->keymenu   = &printer_select_keymenu;
  1364.     ctmpa->help      = NO_HELP;
  1365.     ctmpa->tool      = print_select_tool;
  1366.     ctmpa->flags    |= CF_NOSELECT;
  1367.     ctmpa->value
  1368. #ifdef OS2
  1369.       = cpystr("Using this option may require you to use the OS/2 \"MODE\" command to");
  1370. #else
  1371.       = cpystr("Using this option may require setting your \"PRINTER\" or \"LPDEST\"");
  1372. #endif
  1373.     ctmpa->headingp  = heading;
  1374.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1375.  
  1376.     new_confline(&ctmpa);
  1377.     ctmpa->valoffset = 6;
  1378.     ctmpa->keymenu   = &printer_select_keymenu;
  1379.     ctmpa->help      = NO_HELP;
  1380.     ctmpa->tool      = print_select_tool;
  1381.     ctmpa->flags    |= CF_NOSELECT;
  1382.     ctmpa->value
  1383. #ifdef OS2
  1384.       = cpystr("direct printer output to the correct port.");
  1385. #else
  1386.       = cpystr("environment variable using the standard UNIX utilities.");
  1387. #endif
  1388.     ctmpa->headingp  = heading;
  1389.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1390.  
  1391.     vtmp = &ps->vars[V_STANDARD_PRINTER];
  1392.     for(i = 0; vtmp->current_val.l[i]; i++){
  1393.     new_confline(&ctmpa);
  1394.     ctmpa->valoffset = 22;
  1395.     ctmpa->keymenu   = &printer_select_keymenu;
  1396.     ctmpa->help      = NO_HELP;
  1397.     ctmpa->help      = h_config_set_stand_print;
  1398.     ctmpa->tool      = print_select_tool;
  1399.     if(i == 0){
  1400.         ctmpa->varoffset = 8;
  1401.         ctmpa->varname   = cpystr("Printer List:");
  1402.         ctmpa->flags    |= CF_NOHILITE;
  1403. #ifdef OS2
  1404.         start_line = ctmpb = ctmpa; /* default start line */
  1405. #else
  1406.         ctmpb = ctmpa;
  1407. #endif
  1408.     }
  1409.  
  1410.     ctmpa->varnamep  = ctmpb;
  1411.     ctmpa->headingp  = heading;
  1412.     ctmpa->varmem = i;
  1413.     ctmpa->var = vtmp;
  1414.     ctmpa->value = printer_name(vtmp->current_val.l[i]);
  1415.     }
  1416.  
  1417.     new_confline(&ctmpa);
  1418.     ctmpa->valoffset = 0;
  1419.     ctmpa->keymenu   = &printer_select_keymenu;
  1420.     ctmpa->help      = NO_HELP;
  1421.     ctmpa->tool      = print_select_tool;
  1422.     ctmpa->flags    |= CF_NOSELECT;
  1423.     ctmpa->value = cpystr("");
  1424.  
  1425.     new_confline(&ctmpa);
  1426.     heading = ctmpa;
  1427.     ctmpa->valoffset = 0;
  1428.     ctmpa->keymenu   = &printer_edit_keymenu;
  1429.     ctmpa->help      = NO_HELP;
  1430.     ctmpa->tool      = print_edit_tool;
  1431.     ctmpa->varname
  1432. #ifdef OS2
  1433.         = cpystr(" Personally selected port or |command");
  1434. #else
  1435.     = cpystr(" Personally selected print command");
  1436. #endif
  1437.     ctmpa->flags    |= CF_NOSELECT;
  1438.     ctmpa->value = cpystr("");
  1439.     ctmpa->headingp  = heading;
  1440.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1441.  
  1442.  
  1443.     new_confline(&ctmpa);
  1444.     ctmpa->valoffset = 6;
  1445.     ctmpa->keymenu   = &printer_edit_keymenu;
  1446.     ctmpa->help      = NO_HELP;
  1447.     ctmpa->tool      = print_edit_tool;
  1448.     ctmpa->flags    |= CF_NOSELECT;
  1449.     ctmpa->value
  1450. #ifdef OS2
  1451.       = cpystr("The text to be printed will be sent to the printer or command given here.");
  1452. #else
  1453.       = cpystr("The text to be printed will be piped into the command given here. The");
  1454. #endif
  1455.     ctmpa->headingp  = heading;
  1456.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1457.  
  1458.     new_confline(&ctmpa);
  1459.     ctmpa->valoffset = 6;
  1460.     ctmpa->keymenu   = &printer_edit_keymenu;
  1461.     ctmpa->help      = NO_HELP;
  1462.     ctmpa->tool      = print_edit_tool;
  1463.     ctmpa->flags    |= CF_NOSELECT;
  1464.     ctmpa->value
  1465. #ifdef OS2
  1466.       = cpystr("The printer port or |pipe is in the 2nd column, the printer name is in");
  1467. #else
  1468.       = cpystr("command is in the 2nd column, the printer name is in the first column. Some");
  1469. #endif
  1470.     ctmpa->headingp  = heading;
  1471.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1472.  
  1473.     new_confline(&ctmpa);
  1474.     ctmpa->valoffset = 6;
  1475.     ctmpa->keymenu   = &printer_edit_keymenu;
  1476.     ctmpa->help      = NO_HELP;
  1477.     ctmpa->tool      = print_edit_tool;
  1478.     ctmpa->flags    |= CF_NOSELECT;
  1479.     ctmpa->value
  1480. #ifdef OS2
  1481.       = cpystr("the first column. Examples: \"LPT1\", \"COM2\", \"|enscript\". A command may");
  1482. #else
  1483.       = cpystr("examples are: \"prt\", \"lpr\", \"lp\", or \"enscript\". The command may be given");
  1484. #endif
  1485.     ctmpa->headingp  = heading;
  1486.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1487.  
  1488.     new_confline(&ctmpa);
  1489.     ctmpa->valoffset = 6;
  1490.     ctmpa->keymenu   = &printer_edit_keymenu;
  1491.     ctmpa->help      = NO_HELP;
  1492.     ctmpa->tool      = print_edit_tool;
  1493.     ctmpa->flags    |= CF_NOSELECT;
  1494.     ctmpa->value
  1495. #ifdef OS2
  1496.       = cpystr("be given options, for example \"|ascii2ps -p LPT1\" or \"|txt2hplc -2\". Use");
  1497. #else
  1498.       = cpystr("with options, for example \"enscript -2 -r\" or \"lpr -Plpacc170\". The");
  1499. #endif
  1500.     ctmpa->headingp  = heading;
  1501.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1502.  
  1503.     new_confline(&ctmpa);
  1504.     ctmpa->valoffset = 6;
  1505.     ctmpa->keymenu   = &printer_edit_keymenu;
  1506.     ctmpa->help      = NO_HELP;
  1507.     ctmpa->tool      = print_edit_tool;
  1508.     ctmpa->flags    |= CF_NOSELECT;
  1509.     ctmpa->value
  1510. #ifdef OS2
  1511.       = cpystr("the |command method for printers that require conversion from ASCII.");
  1512. #else
  1513.       = cpystr("commands and options on your system may be different from these examples.");
  1514. #endif
  1515.     ctmpa->headingp  = heading;
  1516.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1517.  
  1518.     vtmp = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1519.     if(vtmp->current_val.l){
  1520.     for(i = 0; vtmp->current_val.l[i]; i++){
  1521.         new_confline(&ctmpa);
  1522.         ctmpa->valoffset = 22;
  1523.         ctmpa->keymenu   = &printer_edit_keymenu;
  1524.         ctmpa->help      = h_config_set_custom_print;
  1525.         ctmpa->tool      = print_edit_tool;
  1526.         if(i == 0){
  1527.         ctmpa->varoffset = 8;
  1528.         ctmpa->varname   = cpystr("Printer List:");
  1529.         ctmpa->flags    |= CF_NOHILITE;
  1530.         ctmpb = ctmpa;
  1531.         }
  1532.  
  1533.         ctmpa->varnamep  = ctmpb;
  1534.         ctmpa->headingp  = heading;
  1535.         ctmpa->varmem = i;
  1536.         ctmpa->var = vtmp;
  1537.         ctmpa->value = printer_name(vtmp->current_val.l[i]);
  1538.     }
  1539.     }
  1540.     else{
  1541.     new_confline(&ctmpa);
  1542.     ctmpa->valoffset = 22;
  1543.     ctmpa->keymenu   = &printer_edit_keymenu;
  1544.     ctmpa->help      = h_config_set_custom_print;
  1545.     ctmpa->tool      = print_edit_tool;
  1546.     ctmpa->flags    |= CF_NOHILITE;
  1547.     ctmpa->varoffset = 8;
  1548.     ctmpa->varname   = cpystr("Printer List:");
  1549.     ctmpa->varnamep  = ctmpa;
  1550.     ctmpa->headingp  = heading;
  1551.     ctmpa->varmem    = 0;
  1552.     ctmpa->var       = vtmp;
  1553.     ctmpa->value     = cpystr("");
  1554.     }
  1555.  
  1556.     vsave = save_config_vars(ps);
  1557.     switch(conf_scroll_screen(ps, start_line, "SELECT PRINTER", PrintConfig)){
  1558.       case 0:
  1559.     break;
  1560.     
  1561.       case 1:
  1562.     write_pinerc(ps);
  1563.     break;
  1564.     
  1565.       case 10:
  1566.     revert_to_saved_config(ps, vsave);
  1567.     ps->printer_category = saved_printer_cat;
  1568.     set_variable(V_PRINTER, saved_printer, 0);
  1569.     set_variable(V_PERSONAL_PRINT_CATEGORY, 
  1570.         comatose(ps->printer_category), 0);
  1571.     break;
  1572.     }
  1573.  
  1574.     def_printer_line = NULL;
  1575.     free_saved_config(ps, &vsave);
  1576.     fs_give((void **)&saved_printer);
  1577. }
  1578. #endif    /* !DOS */
  1579.  
  1580.  
  1581. void
  1582. set_def_printer_value(printer)
  1583.     char *printer;
  1584. {
  1585.     char *p, *nick, *cmd;
  1586.     int set;
  1587.  
  1588.     if(!def_printer_line)
  1589.       return;
  1590.  
  1591.     parse_printer(printer, &nick, &cmd, NULL, NULL, NULL, NULL);
  1592.     p = *nick ? nick : cmd;
  1593.     set = *p;
  1594.     if(*def_printer_line)
  1595.       fs_give((void **)def_printer_line);
  1596.  
  1597.     *def_printer_line = fs_get(36 + strlen(p) + 1);
  1598.     sprintf(*def_printer_line, "Default printer currently %s%s%s",
  1599.     set ? "set to \"" : "unset", set ? p : "", set ? "\"." : "."); 
  1600.  
  1601.     fs_give((void **)&nick);
  1602.     fs_give((void **)&cmd);
  1603. }
  1604.  
  1605.  
  1606. static struct key flag_keys[] = 
  1607.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  1608.     {"E","Exit Flags",KS_EXITMODE}, {"X","[Set/Unset]",KS_NONE},
  1609.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  1610.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  1611.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  1612.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  1613. INST_KEY_MENU(flag_keymenu, flag_keys);
  1614.  
  1615. /*----------------------------------------------------------------------
  1616.    Function to control flag set/clearing
  1617.  
  1618.    Basically, turn the flags into a fake list of features...
  1619.  
  1620.  ----*/
  1621. void
  1622. flag_maintenance_screen(ps, flags)
  1623.     struct pine           *ps;
  1624.     struct flag_screen *flags;
  1625. {
  1626.     int          i, lv;
  1627.     char      tmp[256], **p;
  1628.     CONF_S     *ctmpa = NULL, *ctmpb = NULL, *first_line = NULL;
  1629.     struct      flag_table  *fp;
  1630.     MESSAGECACHE *mc = NULL;
  1631.  
  1632.     for(p = flags->explanation; p && *p; p++){
  1633.     new_confline(&ctmpa);
  1634.     ctmpa->keymenu   = &flag_keymenu;
  1635.     ctmpa->help      = NO_HELP;
  1636.     ctmpa->tool      = flag_checkbox_tool;
  1637.     ctmpa->flags    |= CF_NOSELECT;
  1638.     ctmpa->valoffset = 0;
  1639.     ctmpa->value     = cpystr(*p);
  1640.     }
  1641.  
  1642.     /* Now wire flags checkboxes together */
  1643.     for(lv = 0, fp = flags->flag_table; fp->name; fp++)    /* longest name */
  1644.       if(lv < (i = strlen(fp->name)))
  1645.     lv = i;
  1646.  
  1647.     for(fp = flags->flag_table; fp->name; fp++){    /* build the list */
  1648.     new_confline(&ctmpa);
  1649.     if(!first_line)
  1650.       first_line = ctmpa;
  1651.  
  1652.     ctmpa->varnamep          = ctmpb;
  1653.     ctmpa->keymenu          = &flag_keymenu;
  1654.     ctmpa->help          = fp->help;
  1655.     ctmpa->tool          = flag_checkbox_tool;
  1656.     ctmpa->scrap          = fp;
  1657.     ctmpa->valoffset      = 12;
  1658.  
  1659.     sprintf(tmp, "[%c]  %-*.*s",
  1660.         (fp->set == 0) ? ' ' : (fp->set == 1) ? 'X' : '?',
  1661.         lv, lv, fp->name);
  1662.     ctmpa->value = cpystr(tmp);
  1663.     }
  1664.       
  1665.     (void) conf_scroll_screen(ps, first_line, "FLAG MAINTENANCE", Config);
  1666.     ps->mangled_screen = 1;
  1667. }
  1668.  
  1669.  
  1670. /*
  1671.  * Handles screen painting and motion.  Passes other commands to
  1672.  * custom tools.
  1673.  *
  1674.  * Tool return values:  Tools should return the following:
  1675.  *     0 nothing changed
  1676.  *    -1 unrecognized command
  1677.  *     1 something changed, conf_scroll_screen should remember that
  1678.  *     2 tells conf_scroll_screen to return with value 1 or 0 depending
  1679.  *       on whether or not it has previously gotten a 1 from some tool.
  1680.  *     3 tells conf_scroll_screen to return 1 (like 1 and 2 combined)
  1681.  *     ? Other tool-specific values can be used.  They will cause
  1682.  *       conf_scroll_screen to return that value.
  1683.  *
  1684.  * Return values:
  1685.  *     0 if nothing happened.  That is, a tool returned 2 and we hadn't
  1686.  *       previously noted a return of 1
  1687.  *     1 if something happened.  That is, a tool returned 2 and we had
  1688.  *       previously noted a return of 1
  1689.  *     ? Tool-returned value different from -1, 0, 1, or 2.  This is it.
  1690.  */
  1691. int
  1692. conf_scroll_screen(ps, start_line, title, style)
  1693.     struct pine *ps;
  1694.     CONF_S      *start_line;
  1695.     char        *title;
  1696.     ConfigType   style;
  1697. {
  1698.     char      tmp[MAXPATH+1];
  1699.     int          i, j, ch = 'x', orig_ch, done = 0, changes = 0;
  1700.     int          retval = 0;
  1701.     int          km_popped = 0;
  1702.     struct      key_menu  *km = NULL;
  1703.     CONF_S     *ctmpa = NULL, *ctmpb;
  1704.     OPT_SCREEN_S  screen;
  1705.     NAMEVAL_S     *f;
  1706.     Pos           cursor_pos;
  1707.  
  1708.     memset(&screen, 0, sizeof(OPT_SCREEN_S));
  1709.     screen.first_line = first_sel_confline(start_line);
  1710.     screen.current    = start_line;
  1711.     opt_screen           = &screen;
  1712.     ps->mangled_screen = 1;
  1713.     ps->redrawer       = option_screen_redrawer;
  1714.  
  1715.     while(!done){
  1716.     if(km_popped){
  1717.         km_popped--;
  1718.         if(km_popped == 0){
  1719.         clearfooter(ps);
  1720.         ps->mangled_body = 1;
  1721.         }
  1722.     }
  1723.  
  1724.     if(ps->mangled_screen){
  1725.         ps->mangled_header = 1;
  1726.         ps->mangled_footer = 1;
  1727.         ps->mangled_body   = 1;
  1728.         ps->mangled_screen = 0;
  1729.     }
  1730.  
  1731.     /*----------- Check for new mail -----------*/
  1732.         if(new_mail(0, NM_TIMING(ch), 1) >= 0)
  1733.           ps->mangled_header = 1;
  1734.  
  1735.     if(ps->mangled_header){
  1736.         set_titlebar(title, ps->mail_stream,
  1737.              ps->context_current,
  1738.              ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0);
  1739.         ps->mangled_header = 0;
  1740.     }
  1741.  
  1742.     update_option_screen(ps, &screen, &cursor_pos);
  1743.  
  1744.     if(F_OFF(F_SHOW_CURSOR, ps)){
  1745.         cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
  1746.         cursor_pos.col = 0;
  1747.     }
  1748.  
  1749.     /*---- This displays new mail notification, or errors ---*/
  1750.     if(km_popped){
  1751.         FOOTER_ROWS(ps) = 3;
  1752.         mark_status_unknown();
  1753.     }
  1754.  
  1755.         display_message(ch);
  1756.     if(km_popped){
  1757.         FOOTER_ROWS(ps) = 1;
  1758.         mark_status_unknown();
  1759.     }
  1760.  
  1761.     if(ps->mangled_footer || km != screen.current->keymenu){
  1762.         bitmap_t     bitmap;
  1763.  
  1764.         setbitmap(bitmap);
  1765.  
  1766.         ps->mangled_footer = 0;
  1767.         km                 = screen.current->keymenu;
  1768.         if(km_popped){
  1769.         FOOTER_ROWS(ps) = 3;
  1770.         clearfooter(ps);
  1771.         }
  1772.  
  1773.         draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
  1774.         1-FOOTER_ROWS(ps), 0, FirstMenu,0);
  1775.  
  1776.         if(km_popped){
  1777.         FOOTER_ROWS(ps) = 1;
  1778.         mark_keymenu_dirty();
  1779.         }
  1780.     }
  1781.  
  1782.     MoveCursor(cursor_pos.row, cursor_pos.col);
  1783. #ifdef    MOUSE
  1784.     mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);    /* prime the handler */
  1785.     register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
  1786.                ps_global->ttyo->screen_rows -(FOOTER_ROWS(ps_global)+1),
  1787.                ps_global->ttyo->screen_cols);
  1788. #endif
  1789. #ifdef    _WINDOWS
  1790.     mswin_setscrollcallback(config_scroll_callback);
  1791. #endif
  1792.         /*------ Read the command from the keyboard ----*/
  1793.     ch = orig_ch = read_command();
  1794. #ifdef    MOUSE
  1795.     clear_mfunc(mouse_in_content);
  1796. #endif
  1797. #ifdef    _WINDOWS
  1798.     mswin_setscrollcallback(NULL);
  1799. #endif
  1800.  
  1801.         if(ch <= 0xff && isupper((unsigned char)ch))
  1802.           ch = tolower((unsigned char)ch);
  1803.  
  1804.     if(km_popped)
  1805.       switch(ch){
  1806.         case NO_OP_IDLE:
  1807.         case NO_OP_COMMAND: 
  1808.         case KEY_RESIZE:
  1809.         case ctrl('L'):
  1810.           km_popped++;
  1811.           break;
  1812.         
  1813.         default:
  1814.           clearfooter(ps);
  1815.           break;
  1816.       }
  1817.  
  1818.     switch(ch){
  1819.       case '?' :                /* help! */
  1820.       case ctrl('G'):
  1821.       case PF1 :
  1822.         if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
  1823.         km_popped = 2;
  1824.         ps->mangled_footer = 1;
  1825.         break;
  1826.         }
  1827.  
  1828.         if(screen.current->help != NO_HELP){
  1829.         helper(screen.current->help, CONFIG_SCREEN_HELP_TITLE, 1);
  1830.         ps->mangled_screen = 1;
  1831.         }
  1832.         else
  1833.           q_status_message(SM_ORDER,0,3,"No help yet!");
  1834.  
  1835.         break;
  1836.  
  1837.  
  1838.       case 'n' :                /* next list element */
  1839.       case PF6 :
  1840.       case '\t' :
  1841.       case ctrl('F') :
  1842.       case KEY_RIGHT :
  1843.       case ctrl('N'):            /* down arrow */
  1844.       case KEY_DOWN:
  1845.         for(ctmpa = next_confline(screen.current), i = 1;
  1846.         ctmpa && (ctmpa->flags & CF_NOSELECT);
  1847.         ctmpa = next_confline(ctmpa), i++)
  1848.           ;
  1849.  
  1850.         if(ctmpa){
  1851.         screen.current = ctmpa;
  1852.         if(ch == ctrl('N') || ch == KEY_DOWN){
  1853.             for(ctmpa = screen.top_line,
  1854.             j = BODY_LINES(ps) - 1 - HS_MARGIN(ps);
  1855.             j > 0 && ctmpa && ctmpa != screen.current;
  1856.             ctmpa = next_confline(ctmpa), j--)
  1857.               ;
  1858.  
  1859.             if(!j && ctmpa){
  1860.             for(i = 0;
  1861.                 ctmpa && ctmpa != screen.current;
  1862.                 ctmpa = next_confline(ctmpa), i++)
  1863.               ;
  1864.  
  1865.             if(i)
  1866.               config_scroll_up(i);
  1867.             }
  1868.         }
  1869.         }
  1870.         else
  1871.           q_status_message(SM_ORDER,0,1,"Already at end of screen");
  1872.  
  1873.         break;
  1874.  
  1875.       case 'p' :                /* previous list element */
  1876.       case PF5 :
  1877.       case ctrl('B') :
  1878.       case KEY_LEFT :
  1879.       case ctrl('P') :            /* up arrow */
  1880.       case KEY_UP :
  1881.         ctmpa = screen.current;
  1882.         i = 0;
  1883.         do
  1884.           if(ctmpa == config_top_scroll(ps, screen.top_line))
  1885.         i = 1;
  1886.           else if(i)
  1887.         i++;
  1888.         while((ctmpa = prev_confline(ctmpa))
  1889.           && (ctmpa->flags&CF_NOSELECT));
  1890.  
  1891.         if(ctmpa){
  1892.         screen.current = ctmpa;
  1893.         if((ch == ctrl('P') || ch == KEY_UP) && i)
  1894.           config_scroll_down(i);
  1895.         }
  1896.         else
  1897.           q_status_message(SM_ORDER, 0, 1,
  1898.                    "Already at start of screen");
  1899.  
  1900.         break;
  1901.  
  1902.       case '+' :                /* page forward */
  1903.       case ' ' :
  1904.       case ctrl('V') :
  1905.       case PF8 :
  1906.       case KEY_PGDN:
  1907.         for(ctmpa = screen.top_line, i = BODY_LINES(ps);
  1908.         i > 0 && ctmpa;
  1909.         ctmpa = next_confline(ctmpa), i--)
  1910.           ;
  1911.  
  1912.         if(ctmpa){
  1913.         ps->mangled_body = 1;
  1914.         for(screen.top_line = ctmpa;
  1915.             ctmpa && (ctmpa->flags & CF_NOSELECT);
  1916.             ctmpa = next_confline(ctmpa))
  1917.           ;
  1918.         }
  1919.         else{  /* on last screen */
  1920.         for(ctmpa = screen.top_line, i = BODY_LINES(ps) - i - 1;
  1921.             i > 0 && ctmpa;
  1922.             ctmpa = next_confline(ctmpa), i--)
  1923.           ;
  1924.         
  1925.         /* ctmpa is pointing at last line now */
  1926.         if(ctmpa){
  1927.             for(; ctmpa && (ctmpa->flags & CF_NOSELECT);
  1928.             ctmpa = prev_confline(ctmpa))
  1929.               ;
  1930.  
  1931.             if(ctmpa == screen.current)
  1932.               q_status_message(SM_ORDER,0,1,
  1933.                   "Already at end of screen");
  1934.             else
  1935.               ps->mangled_body = 1;
  1936.         }
  1937.         }
  1938.  
  1939.         if(ctmpa)
  1940.           screen.current = ctmpa;
  1941.  
  1942.         break;
  1943.  
  1944.       case '-' :                /* page backward */
  1945.       case ctrl('Y') :
  1946.       case PF7 :
  1947.       case KEY_PGUP:
  1948.         ps->mangled_body = 1;
  1949.         if(!(ctmpa=prev_confline(screen.top_line)))
  1950.           ctmpa = screen.current;
  1951.  
  1952.         for(i = BODY_LINES(ps) - 1;
  1953.         i > 0 && prev_confline(ctmpa);
  1954.         i--, ctmpa = prev_confline(ctmpa))
  1955.           ;
  1956.  
  1957.         for(screen.top_line = ctmpa;
  1958.             ctmpa && (ctmpa->flags & CF_NOSELECT);
  1959.         ctmpa = next_confline(ctmpa))
  1960.           ;
  1961.  
  1962.         if(ctmpa){
  1963.         if(ctmpa == screen.current)
  1964.           q_status_message(SM_ORDER, 0, 1,
  1965.                  "Already at start of screen");
  1966.  
  1967.         screen.current = ctmpa;
  1968.         }
  1969.  
  1970.         break;
  1971.  
  1972. #ifdef MOUSE        
  1973.       case KEY_MOUSE:
  1974.         {   
  1975.         MOUSEPRESS mp;
  1976.  
  1977.         mouse_get_last (NULL, &mp);
  1978.         mp.row -= HEADER_ROWS(ps);
  1979.         ctmpa = screen.top_line;
  1980.         if (mp.doubleclick) {
  1981.             if(screen.current->tool){
  1982.             unsigned flags;
  1983.  
  1984.             flags  = screen.current->flags;
  1985.             flags |= (changes ? CF_CHANGES : 0);
  1986.  
  1987.             switch(i=(*screen.current->tool)(ps, ctrl('M'),
  1988.                 &screen.current, flags)){
  1989.               case -1:
  1990.               case 0:
  1991.                 break;
  1992.  
  1993.               case 1:
  1994.                 changes = 1;
  1995.                 break;
  1996.  
  1997.               case 2:
  1998.                 retval = changes;
  1999.                 done++;
  2000.                 break;
  2001.  
  2002.               case 3:
  2003.                 retval = 1;
  2004.                 done++;
  2005.                 break;
  2006.  
  2007.               default:
  2008.                 retval = i;
  2009.                 done++;
  2010.                 break;
  2011.             }
  2012.             }
  2013.         }
  2014.         else {
  2015.             while (mp.row && ctmpa != NULL) {
  2016.             --mp.row;
  2017.             ctmpa = ctmpa->next;
  2018.             }
  2019.  
  2020.             if (ctmpa != NULL && !(ctmpa->flags & CF_NOSELECT))
  2021.               screen.current = ctmpa;
  2022.         }
  2023.         }
  2024.         break;
  2025. #endif
  2026.  
  2027.       case 'y' :                /* print screen */
  2028.       case PF11:
  2029.       case PF2 :
  2030.         if((style == NoPrint)
  2031.           || (ch == PF11 && style == PrintConfig)
  2032.           || (ch == PF2 && style != PrintConfig))
  2033.           goto let_tool_handle_it;
  2034.  
  2035.         print_option_screen(&screen, style==Config ? "configuration "
  2036.         : style==PrintConfig ? "printer config " : "");
  2037.         break;
  2038.  
  2039.       case 'w' :                /* whereis */
  2040.       case ctrl('W') :
  2041.       case PF12 :
  2042.         /*--- get string  ---*/
  2043.         {int   rc, found = 0;
  2044.          char *result = NULL, buf[64];
  2045.          static char last[64];
  2046.          HelpType help;
  2047.          static ESCKEY_S ekey[] = {
  2048.         {0, 0, "", ""},
  2049.         {ctrl('Y'), 10, "^Y", "Top"},
  2050.         {ctrl('V'), 11, "^V", "Bottom"},
  2051.         {-1, 0, NULL, NULL}};
  2052.  
  2053.          ps->mangled_footer = 1;
  2054.          buf[0] = '\0';
  2055.          sprintf(tmp, "Word to find %s%s%s: ",
  2056.              (last[0]) ? "[" : "",
  2057.              (last[0]) ? last : "",
  2058.              (last[0]) ? "]" : "");
  2059.          help = NO_HELP;
  2060.          while(1){
  2061.          rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,63,1,0,
  2062.                      tmp,ekey,help,0);
  2063.          if(rc == 3)
  2064.            help = help == NO_HELP ? h_config_whereis : NO_HELP;
  2065.          else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
  2066.              if(rc == 0 && !buf[0] && last[0])
  2067.                strcpy(buf, last);
  2068.  
  2069.              break;
  2070.          }
  2071.          }
  2072.  
  2073.          if(rc == 0 && buf[0]){
  2074.          ch   = KEY_DOWN;
  2075.          ctmpa = screen.current;
  2076.          while(ctmpa = next_confline(ctmpa))
  2077.            if(srchstr(ctmpa->varname, buf)
  2078.               || srchstr(ctmpa->value, buf)){
  2079.                while(ctmpa && (ctmpa->flags & CF_NOSELECT))
  2080.              ctmpa = next_confline(ctmpa);
  2081.  
  2082.                if(ctmpa)
  2083.              found++;
  2084.  
  2085.                break;
  2086.            }
  2087.  
  2088.          if(!found){
  2089.              ctmpa = first_confline(screen.current);
  2090.  
  2091.              while(ctmpa != screen.current)
  2092.                if(srchstr(ctmpa->varname, buf)
  2093.               || srchstr(ctmpa->value, buf)){
  2094.                while(ctmpa && ctmpa != screen.current
  2095.                  && (ctmpa->flags & CF_NOSELECT))
  2096.                  ctmpa = next_confline(ctmpa);
  2097.  
  2098.                if(ctmpa && ctmpa != screen.current)
  2099.                  found++;
  2100.  
  2101.                break;
  2102.                }
  2103.                else
  2104.              ctmpa = next_confline(ctmpa);
  2105.          }
  2106.          }
  2107.          else if(rc == 10){
  2108.          screen.current = first_confline(screen.current);
  2109.          result = "Searched to top";
  2110.          }
  2111.          else if(rc == 11){
  2112.          screen.current = last_confline(screen.current);
  2113.          result = "Searched to bottom";
  2114.          }
  2115.          else
  2116.            result = "WhereIs cancelled";
  2117.  
  2118.          if(found && ctmpa){
  2119.          strcpy(last, buf);
  2120.          result  = "Word found";
  2121.          screen.current = ctmpa;
  2122.          }
  2123.  
  2124.          q_status_message(SM_ORDER,0,3,result ? result : "Word not found");
  2125.         }
  2126.  
  2127.         break;
  2128.  
  2129.       case ctrl('L'):            /* redraw the display */
  2130.           case KEY_RESIZE:
  2131.         ClearScreen();
  2132.         ps->mangled_screen = 1;
  2133.         break;
  2134.  
  2135.       let_tool_handle_it:
  2136.       default:
  2137.         if(ps_global->restricted || ps_global->readonly_pinerc){
  2138.         q_status_message1(SM_ORDER, 0, 3,
  2139.              "%s can't change options or settings",
  2140.              ps_global->restricted ? "Pine demo"
  2141.                        : "Config file not editable,");
  2142.         if(ch == 'e' || ch == PF3){
  2143.             retval = 0;
  2144.             done++;
  2145.         }
  2146.         }
  2147.         else if(screen.current->tool){
  2148.         unsigned flags;
  2149.  
  2150.         flags  = screen.current->flags;
  2151.         flags |= (changes ? CF_CHANGES : 0);
  2152.  
  2153.         switch(i=(*screen.current->tool)(ps, ch,
  2154.             &screen.current, flags)){
  2155.           case -1:
  2156.             q_status_message2(SM_ORDER, 0, 2,
  2157.               "Command \"%s\" not defined here.%s",
  2158.               pretty_command(orig_ch),
  2159.               F_ON(F_BLANK_KEYMENU,ps) ? "" : "  See key menu below.");
  2160.             break;
  2161.  
  2162.           case 0:
  2163.             break;
  2164.  
  2165.           case 1:
  2166.             changes = 1;
  2167.             break;
  2168.  
  2169.           case 2:
  2170.             retval = changes;
  2171.             done++;
  2172.             break;
  2173.  
  2174.           case 3:
  2175.             retval = 1;
  2176.             done++;
  2177.             break;
  2178.  
  2179.           default:
  2180.             retval = i;
  2181.             done++;
  2182.             break;
  2183.         }
  2184.         }
  2185.  
  2186.         break;
  2187.  
  2188.       case NO_OP_IDLE:            /* simple timeout */
  2189.       case NO_OP_COMMAND:
  2190.         break;
  2191.     }
  2192.     }
  2193.  
  2194.     for(screen.current = first_confline(screen.current); screen.current;){
  2195.     ctmpa = screen.current->next;        /* clean up */
  2196.     free_confline(&screen.current);
  2197.     screen.current = ctmpa;
  2198.     }
  2199.  
  2200.     return(retval);
  2201. }
  2202.  
  2203.  
  2204. /*
  2205.  *
  2206.  */
  2207. int
  2208. config_scroll_up(n)
  2209.     long n;
  2210. {
  2211.     CONF_S *ctmp = opt_screen->top_line;
  2212.     int     cur_found = 0, rv = 1;
  2213.  
  2214.     if(n < 0)
  2215.       return(config_scroll_down(-n));
  2216.     else if(n){
  2217.     while(n-- && (ctmp = next_confline(ctmp)))
  2218.       if(prev_confline(ctmp) == opt_screen->current)
  2219.         cur_found++;
  2220.  
  2221.     if(ctmp){
  2222.         opt_screen->top_line = ctmp;
  2223.         rv = ps_global->mangled_body = 1;
  2224.         if(cur_found){
  2225.         for(ctmp = opt_screen->top_line;
  2226.             ctmp && (ctmp->flags & CF_NOSELECT);
  2227.             ctmp = next_confline(ctmp))
  2228.           ;
  2229.  
  2230.         if(ctmp)
  2231.           opt_screen->current = opt_screen->prev = ctmp;
  2232.         }
  2233.     }
  2234.     else
  2235.       rv = 0;
  2236.     }
  2237.  
  2238.     return(rv);
  2239. }
  2240.  
  2241.  
  2242. /*
  2243.  * config_scroll_down -
  2244.  */
  2245. int
  2246. config_scroll_down(n)
  2247.     long n;
  2248. {
  2249.     CONF_S *ctmp = opt_screen->top_line, *last_sel = NULL;
  2250.     int     i, rv = 1;
  2251.  
  2252.     if(n < 0)
  2253.       return(config_scroll_up(-n));
  2254.     else if(n){
  2255.     while(n-- && (ctmp = prev_confline(ctmp)))
  2256.       ;
  2257.  
  2258.     if(ctmp){
  2259.         opt_screen->top_line = ctmp;
  2260.         rv = ps_global->mangled_body = 1;
  2261.         for(ctmp = opt_screen->top_line, i = BODY_LINES(ps_global);
  2262.         i > 0 && ctmp && ctmp != opt_screen->current;
  2263.         ctmp = next_confline(ctmp), i--)
  2264.           if(!(ctmp->flags & CF_NOSELECT))
  2265.         last_sel = ctmp;
  2266.  
  2267.         if(!i && last_sel)
  2268.           opt_screen->current = opt_screen->prev = last_sel;
  2269.     }
  2270.     else
  2271.       rv = 0;
  2272.     }
  2273.  
  2274.     return(rv);
  2275. }
  2276.  
  2277.  
  2278. /*
  2279.  * config_scroll_to_pos -
  2280.  */
  2281. int
  2282. config_scroll_to_pos(n)
  2283.     long n;
  2284. {
  2285.     CONF_S *ctmp;
  2286.  
  2287.     for(ctmp = first_confline(opt_screen->current);
  2288.     n && ctmp && ctmp != opt_screen->top_line;
  2289.     ctmp = next_confline(ctmp), n--)
  2290.       ;
  2291.  
  2292.     if(n == 0)
  2293.       while(ctmp && ctmp != opt_screen->top_line)
  2294.     if(ctmp = next_confline(ctmp))
  2295.       n--;
  2296.  
  2297.     return(config_scroll_up(n));
  2298. }
  2299.  
  2300.  
  2301. /*
  2302.  * config_top_scroll - return pointer to the 
  2303.  */
  2304. CONF_S *
  2305. config_top_scroll(ps, topline)
  2306.     struct pine *ps;
  2307.     CONF_S *topline;
  2308. {
  2309.     int     i;
  2310.     CONF_S *ctmp;
  2311.  
  2312.     for(ctmp = topline, i = HS_MARGIN(ps);
  2313.     ctmp && i;
  2314.     ctmp = next_confline(ctmp), i--)
  2315.       ;
  2316.  
  2317.     return(ctmp ? ctmp : topline);
  2318. }
  2319.  
  2320.  
  2321. /*
  2322.  *
  2323.  */
  2324. HelpType
  2325. config_help(var, feature)
  2326.     int var, feature;
  2327. {
  2328.     switch(var){
  2329.       case V_FEATURE_LIST :
  2330.     switch(feature){
  2331.       case F_ENABLE_FULL_HDR :
  2332.         return(h_config_enable_full_hdr);
  2333.       case F_ENABLE_PIPE :
  2334.         return(h_config_enable_pipe);
  2335.       case F_ENABLE_TAB_COMPLETE :
  2336.         return(h_config_enable_tab_complete);
  2337.       case F_QUIT_WO_CONFIRM :
  2338.         return(h_config_quit_wo_confirm);
  2339.       case F_ENABLE_JUMP :
  2340.         return(h_config_enable_jump);
  2341.       case F_ENABLE_ALT_ED :
  2342.         return(h_config_enable_alt_ed);
  2343.       case F_ENABLE_BOUNCE :
  2344.         return(h_config_enable_bounce);
  2345.       case F_ENABLE_AGG_OPS :
  2346.         return(h_config_enable_agg_ops);
  2347.       case F_ENABLE_FLAG :
  2348.         return(h_config_enable_flag);
  2349.       case F_FLAG_SCREEN_DFLT :
  2350.         return(h_config_flag_screen_default);
  2351.       case F_CAN_SUSPEND :
  2352.         return(h_config_can_suspend);
  2353.       case F_EXPANDED_ADDRBOOKS :
  2354.         return(h_config_expanded_addrbooks);
  2355.       case F_EXPANDED_DISTLISTS :
  2356.         return(h_config_expanded_distlists);
  2357.       case F_FROM_DELIM_IN_PRINT :
  2358.         return(h_config_print_from);
  2359.       case F_EXPANDED_FOLDERS :
  2360.         return(h_config_expanded_folders);
  2361.       case F_USE_FK :
  2362.         return(h_config_use_fk);
  2363.       case F_INCLUDE_HEADER :
  2364.         return(h_config_include_header);
  2365.       case F_SIG_AT_BOTTOM :
  2366.         return(h_config_sig_at_bottom);
  2367.       case F_DEL_SKIPS_DEL :
  2368.         return(h_config_del_skips_del);
  2369.       case F_AUTO_EXPUNGE :
  2370.         return(h_config_auto_expunge);
  2371.       case F_AUTO_READ_MSGS :
  2372.         return(h_config_auto_read_msgs);
  2373.       case F_READ_IN_NEWSRC_ORDER :
  2374.         return(h_config_read_in_newsrc_order);
  2375.       case F_SELECT_WO_CONFIRM :
  2376.         return(h_config_select_wo_confirm);
  2377.       case F_COMPOSE_TO_NEWSGRP :
  2378.         return(h_config_compose_news_wo_conf);
  2379.       case F_USE_CURRENT_DIR :
  2380.         return(h_config_use_current_dir);
  2381.       case F_USE_SENDER_NOT_X :
  2382.         return(h_config_use_sender_not_x);
  2383.       case F_SAVE_WONT_DELETE :
  2384.         return(h_config_save_wont_delete);
  2385.       case F_SAVE_ADVANCES :
  2386.         return(h_config_save_advances);
  2387.       case F_FORCE_LOW_SPEED :
  2388.         return(h_config_force_low_speed);
  2389.       case F_ALT_ED_NOW :
  2390.         return(h_config_alt_ed_now);
  2391.       case F_SHOW_DELAY_CUE :
  2392.         return(h_config_show_delay_cue);
  2393.       case F_DISABLE_CONFIG_SCREEN :
  2394.         return(h_config_disable_config_screen);
  2395.       case F_DISABLE_PASSWORD_CMD :
  2396.         return(h_config_disable_password_cmd);
  2397.       case F_DISABLE_UPDATE_CMD :
  2398.         return(h_config_disable_update_cmd);
  2399.       case F_DISABLE_KBLOCK_CMD :
  2400.         return(h_config_disable_kblock_cmd);
  2401.       case F_QUOTE_ALL_FROMS :
  2402.         return(h_config_quote_all_froms);
  2403.       case F_AUTO_OPEN_NEXT_UNREAD :
  2404.         return(h_config_auto_open_unread);
  2405.       case F_AUTO_INCLUDE_IN_REPLY :
  2406.         return(h_config_auto_include_reply);
  2407.       case F_SELECTED_SHOWN_BOLD :
  2408.         return(h_config_select_in_bold);
  2409.       case F_NO_NEWS_VALIDATION :
  2410.         return(h_config_post_wo_validation);
  2411.       case F_ENABLE_INCOMING :
  2412.         return(h_config_enable_incoming);
  2413.       case F_ATTACHMENTS_IN_REPLY :
  2414.         return(h_config_attach_in_reply);
  2415.       case F_QUELL_LOCAL_LOOKUP :
  2416.         return(h_config_quell_local_lookup);
  2417.       case F_PRESERVE_START_STOP :
  2418.         return(h_config_preserve_start_stop);
  2419.       case F_COMPOSE_REJECTS_UNQUAL:
  2420.         return(h_config_compose_rejects_unqual);
  2421.       case F_FAKE_NEW_IN_NEWS:
  2422.         return(h_config_news_uses_recent);
  2423.       case F_SUSPEND_SPAWNS:
  2424.         return(h_config_suspend_spawns);
  2425.       case F_ENABLE_8BIT:
  2426.         return(h_config_8bit_smtp);
  2427.       case F_ENABLE_8BIT_NNTP:
  2428.         return(h_config_8bit_nntp);
  2429.       case F_COMPOSE_MAPS_DEL:
  2430.         return(h_config_compose_maps_del);
  2431.       case F_BACKGROUND_POST:
  2432.         return(h_config_compose_bg_post);
  2433.       case F_AUTO_ZOOM:
  2434.         return(h_config_auto_zoom);
  2435.       case F_AUTO_UNZOOM:
  2436.         return(h_config_auto_unzoom);
  2437.       case F_DEL_FROM_DOT:
  2438.         return(h_config_del_from_dot);
  2439.       case F_PRINT_INDEX:
  2440.         return(h_config_print_index);
  2441. #if !defined(DOS) && !defined(OS2)
  2442.       case F_ALLOW_TALK:
  2443.         return(h_config_allow_talk);
  2444. #endif
  2445.       case F_ENABLE_MOUSE:
  2446.         return(h_config_enable_mouse);
  2447.       case F_ENABLE_XTERM_NEWMAIL:
  2448.         return(h_config_enable_xterm_newmail);
  2449.       case F_ENABLE_DOT_FILES:
  2450.         return(h_config_enable_dot_files);
  2451.       case F_ENABLE_DOT_FOLDERS:
  2452.         return(h_config_enable_dot_folders);
  2453.       case F_AGG_PRINT_FF:
  2454.         return(h_config_ff_between_msgs);
  2455.       case F_FIRST_SEND_FILTER_DFLT:
  2456.         return(h_config_send_filter_dflt);
  2457.       case F_CUSTOM_PRINT:
  2458.         return(h_config_custom_print);
  2459.       case F_BLANK_KEYMENU:
  2460.         return(h_config_blank_keymenu);
  2461.       case F_FCC_ON_BOUNCE:
  2462.         return(h_config_fcc_on_bounce);
  2463.       case F_PASS_CONTROL_CHARS:
  2464.         return(h_config_pass_control);
  2465.       case F_SHOW_CURSOR:
  2466.         return(h_config_show_cursor);
  2467.       case F_VERT_FOLDER_LIST:
  2468.         return(h_config_vert_list);
  2469.       case F_VERBOSE_POST:
  2470.         return(h_config_verbose_post);
  2471.       case F_AUTO_REPLY_TO:
  2472.         return(h_config_auto_reply_to);
  2473.       case F_TAB_TO_NEW:
  2474.         return(h_config_tab_new_only);
  2475.       case F_QUELL_DEAD_LETTER:
  2476.         return(h_config_quell_dead_letter);
  2477.       case F_QUELL_BEEPS:
  2478.         return(h_config_quell_beeps);
  2479.       case F_QUELL_LOCK_FAILURE_MSGS:
  2480.         return(h_config_quell_lock_failure_warnings);
  2481.       case F_ENABLE_SPACE_AS_TAB :
  2482.         return(h_config_cruise_mode);
  2483.       case F_ENABLE_TAB_DELETES :
  2484.         return(h_config_cruise_mode_delete);
  2485.       case F_ALLOW_GOTO :
  2486.         return(h_config_allow_goto);
  2487.       default :
  2488.         return(NO_HELP);
  2489.         }
  2490.  
  2491.     break;
  2492.  
  2493.       case V_PERSONAL_NAME :
  2494.     return(h_config_pers_name);
  2495.       case V_USER_ID :
  2496.     return(h_config_user_id);
  2497.       case V_USER_DOMAIN :
  2498.     return(h_config_user_dom);
  2499.       case V_SMTP_SERVER :
  2500.     return(h_config_smtp_server);
  2501.       case V_NNTP_SERVER :
  2502.     return(h_config_nntp_server);
  2503.       case V_INBOX_PATH :
  2504.     return(h_config_inbox_path);
  2505.       case V_FOLDER_SPEC :
  2506.     return(h_config_folder_spec);
  2507.       case V_PRUNED_FOLDERS :
  2508.     return(h_config_pruned_folders);
  2509.       case V_NEWS_SPEC :
  2510.     return(h_config_news_spec);
  2511.       case V_DEFAULT_FCC :
  2512.     return(h_config_default_fcc);
  2513.       case V_DEFAULT_SAVE_FOLDER :
  2514.     return(h_config_def_save_folder);
  2515.       case V_POSTPONED_FOLDER :
  2516.     return(h_config_postponed_folder);
  2517.       case V_READ_MESSAGE_FOLDER :
  2518.     return(h_config_read_message_folder);
  2519.       case V_ARCHIVED_FOLDERS :
  2520.     return(h_config_archived_folders);
  2521.       case V_SIGNATURE_FILE :
  2522.     return(h_config_signature_file);
  2523.       case V_GLOB_ADDRBOOK :
  2524.     return(h_config_global_addrbook);
  2525.       case V_ADDRESSBOOK :
  2526.     return(h_config_addressbook);
  2527.       case V_INIT_CMD_LIST :
  2528.     return(h_config_init_cmd_list);
  2529.       case V_COMP_HDRS :
  2530.     return(h_config_comp_hdrs);
  2531.       case V_CUSTOM_HDRS :
  2532.     return(h_config_custom_hdrs);
  2533.       case V_VIEW_HEADERS :
  2534.     return(h_config_viewer_headers);
  2535.       case V_SAVED_MSG_NAME_RULE :
  2536.     return(h_config_saved_msg_name_rule);
  2537.       case V_FCC_RULE :
  2538.     return(h_config_fcc_rule);
  2539.       case V_SORT_KEY :
  2540.     return(h_config_sort_key);
  2541.       case V_AB_SORT_RULE :
  2542.     return(h_config_ab_sort_rule);
  2543.       case V_CHAR_SET :
  2544.     return(h_config_char_set);
  2545.       case V_EDITOR :
  2546.     return(h_config_editor);
  2547.       case V_SPELLER :
  2548.     return(h_config_speller);
  2549.       case V_DISPLAY_FILTERS :
  2550.     return(h_config_display_filters);
  2551.       case V_SEND_FILTER :
  2552.     return(h_config_sending_filter);
  2553.       case V_ALT_ADDRS :
  2554.     return(h_config_alt_addresses);
  2555.       case V_ABOOK_FORMATS :
  2556.     return(h_config_abook_formats);
  2557.       case V_INDEX_FORMAT :
  2558.     return(h_config_index_format);
  2559.       case V_OVERLAP :
  2560.     return(h_config_viewer_overlap);
  2561.       case V_MARGIN :
  2562.     return(h_config_scroll_margin);
  2563.       case V_FILLCOL :
  2564.     return(h_config_composer_wrap_column);
  2565.       case V_REPLY_STRING :
  2566.     return(h_config_reply_indent_string);
  2567.       case V_EMPTY_HDR_MSG :
  2568.     return(h_config_empty_hdr_msg);
  2569.       case V_STATUS_MSG_DELAY :
  2570.     return(h_config_status_msg_delay);
  2571.       case V_MAILCHECK :
  2572.     return(h_config_mailcheck);
  2573.       case V_NEWS_ACTIVE_PATH :
  2574.     return(h_config_news_active);
  2575.       case V_NEWS_SPOOL_DIR :
  2576.     return(h_config_news_spool);
  2577.       case V_IMAGE_VIEWER :
  2578.     return(h_config_image_viewer);
  2579.       case V_USE_ONLY_DOMAIN_NAME :
  2580.     return(h_config_domain_name);
  2581.       case V_LAST_TIME_PRUNE_QUESTION :
  2582.     return(h_config_prune_date);
  2583.       case V_UPLOAD_CMD:
  2584.     return(h_config_upload_cmd);
  2585.       case V_UPLOAD_CMD_PREFIX:
  2586.     return(h_config_upload_prefix);
  2587.       case V_DOWNLOAD_CMD:
  2588.     return(h_config_download_cmd);
  2589.       case V_DOWNLOAD_CMD_PREFIX:
  2590.     return(h_config_download_prefix);
  2591.       case V_GOTO_DEFAULT_RULE:
  2592.     return(h_config_goto_default);
  2593.       case V_MAILCAP_PATH :
  2594.     return(h_config_mailcap_path);
  2595.       case V_MIMETYPE_PATH :
  2596.     return(h_config_mimetype_path);
  2597.       case V_NEWSRC_PATH :
  2598.     return(h_config_newsrc_path);
  2599. #if defined(DOS) || defined(OS2)
  2600.       case V_FOLDER_EXTENSION :
  2601.     return(h_config_folder_extension);
  2602.       case V_NORM_FORE_COLOR :
  2603.     return(h_config_normal_fg);
  2604.       case V_NORM_BACK_COLOR :
  2605.     return(h_config_normal_bg);
  2606.       case V_REV_FORE_COLOR :
  2607.     return(h_config_reverse_fg);
  2608.       case V_REV_BACK_COLOR :
  2609.     return(h_config_reverse_bg);
  2610. #endif
  2611.       default :
  2612.     return(NO_HELP);
  2613.     }
  2614. }
  2615.  
  2616.  
  2617. /*
  2618.  * simple text variable handler
  2619.  *
  2620.  * note, things get a little involved due to the
  2621.  *     screen struct <--> variable mapping. (but, once its
  2622.  *       running it shouldn't need changing ;).
  2623.  * 
  2624.  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
  2625.  *           returns what conf_exit_cmd returns for exit command.
  2626.  */
  2627. int
  2628. text_tool(ps, cmd, cl, flags)
  2629.     struct pine  *ps;
  2630.     int          cmd;
  2631.     CONF_S      **cl;
  2632.     unsigned      flags;
  2633. {
  2634.     char         prompt[81], sval[MAXPATH+1], *tmp, **newval = NULL;
  2635.     int             rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
  2636.     int             lowrange, hirange, incr;
  2637.     int             numval, repeat_key = 0;
  2638.     CONF_S        *ctmp;
  2639.     HelpType         help;
  2640.     ESCKEY_S         ekey[6];
  2641.  
  2642.     if(flags&CF_NUMBER){ /* only happens if !is_list */
  2643.     incr = 1;
  2644.     if((*cl)->var == &ps->vars[V_FILLCOL]){
  2645.         lowrange = 1;
  2646.         hirange  = MAX_FILLCOL;
  2647.     }
  2648.     else if((*cl)->var == &ps->vars[V_OVERLAP]
  2649.         || (*cl)->var == &ps->vars[V_MARGIN]){
  2650.         lowrange = 0;
  2651.         hirange  = 20;
  2652.     }
  2653.     else if((*cl)->var == &ps->vars[V_STATUS_MSG_DELAY]){
  2654.         lowrange = 0;
  2655.         hirange  = 30;
  2656.     }
  2657.     else if((*cl)->var == &ps->vars[V_MAILCHECK]){
  2658.         lowrange = 0;
  2659.         hirange  = 25000;
  2660.         incr     = 15;
  2661.     }
  2662.  
  2663.     ekey[0].ch    = -2;
  2664.     ekey[0].rval  = 'x';
  2665.     ekey[0].name  = "";
  2666.     ekey[0].label = "";
  2667.     ekey[1].ch    = ctrl('P');
  2668.     ekey[1].rval  = ctrl('P');
  2669.     ekey[1].name  = "^P";
  2670.     ekey[1].label = "Decrease";
  2671.     ekey[2].ch    = ctrl('N');
  2672.     ekey[2].rval  = ctrl('N');
  2673.     ekey[2].name  = "^N";
  2674.     ekey[2].label = "Increase";
  2675.     ekey[3].ch    = KEY_DOWN;
  2676.     ekey[3].rval  = ctrl('P');
  2677.     ekey[3].name  = "";
  2678.     ekey[3].label = "";
  2679.     ekey[4].ch    = KEY_UP;
  2680.     ekey[4].rval  = ctrl('N');
  2681.     ekey[4].name  = "";
  2682.     ekey[4].label = "";
  2683.     ekey[5].ch    = -1;
  2684.     }
  2685.  
  2686.     sval[0] = '\0';
  2687.     switch(cmd){
  2688.       case 'a' :                /* add to list */
  2689.       case PF9 :
  2690.     if((*cl)->var->is_fixed){
  2691.         q_status_message(SM_ORDER, 3, 3,
  2692.                  "Can't add to sys-admin defined value.");
  2693.     }
  2694.     else if(!(*cl)->var->is_list && (*cl)->var->user_val.p){
  2695.         q_status_message(SM_ORDER, 3, 3,
  2696.                 "Only single value allowed.  Use \"Change\".");
  2697.     }
  2698.     else{
  2699.         int maxwidth =min(80,ps->ttyo->screen_cols) - 15;
  2700.         char *p;
  2701.  
  2702.         if((*cl)->var->is_list
  2703.            && (*cl)->var->user_val.l
  2704.            && (*cl)->var->user_val.l[0]
  2705.            && (*cl)->var->user_val.l[0][0]
  2706.            && (*cl)->value){
  2707.         char tmpval[101];
  2708.         /* regular add to an existing list */
  2709.  
  2710.         strncpy(tmpval, (*cl)->value, 100);
  2711.         removing_trailing_white_space(tmpval);
  2712.         /* 33 is the number of chars other than the value */
  2713.         k = min(18, max(maxwidth-33,0));
  2714.         if(strlen(tmpval) > k && k >= 3){
  2715.             tmpval[k-1] = tmpval[k-2] = tmpval[k-3] = '.';
  2716.             tmpval[k] = '\0';
  2717.         }
  2718.  
  2719.         sprintf(prompt,
  2720.             "Enter text to insert before \"%.*s\": ",k,tmpval);
  2721.         }
  2722.         else if((*cl)->var->is_list
  2723.             && !(*cl)->var->user_val.l
  2724.             && (*cl)->var->current_val.l){
  2725.         /* Add to list which doesn't exist, but default does exist */
  2726.         ekey[0].ch    = 'r';
  2727.         ekey[0].rval  = 'r';
  2728.         ekey[0].name  = "R";
  2729.         ekey[0].label = "Replace";
  2730.         ekey[1].ch    = 'a';
  2731.         ekey[1].rval  = 'a';
  2732.         ekey[1].name  = "A";
  2733.         ekey[1].label = "Add To";
  2734.         ekey[2].ch    = -1;
  2735.         strcpy(prompt, "Replace or Add To default value ? ");
  2736.         switch(radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a', 'x',
  2737.                      h_config_replace_add, RB_NORM)){
  2738.           case 'a':
  2739.             p = sval;
  2740.             for(j = 0; (*cl)->var->current_val.l[j]; j++){
  2741.             strcpy(p, (*cl)->var->current_val.l[j]);
  2742.             p += strlen(p);
  2743.             *p++ = ',';
  2744.             *p++ = ' ';
  2745.             *p = '\0';
  2746.             }
  2747.  
  2748. add_text:
  2749.             sprintf(prompt, "Enter the %stext to be added : ",
  2750.             flags&CF_NUMBER ? "numeric " : "");
  2751.             break;
  2752.             
  2753.           case 'r':
  2754. replace_text:
  2755.             sprintf(prompt, "Enter the %sreplacement text : ",
  2756.             flags&CF_NUMBER ? "numeric " : "");
  2757.             break;
  2758.             
  2759.           case 'x':
  2760.             i = 1;
  2761.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  2762.             break;
  2763.         }
  2764.         }
  2765.         else
  2766.           sprintf(prompt, "Enter the %stext to be added : ",
  2767.             flags&CF_NUMBER ? "numeric " : "");
  2768.  
  2769.         ps->mangled_footer = 1;
  2770.         help = NO_HELP;
  2771.         while(1){
  2772.         if((*cl)->var->is_list
  2773.             && (*cl)->var->user_val.l
  2774.             && (*cl)->var->user_val.l[0]
  2775.             && (*cl)->var->user_val.l[0][0]
  2776.             && (*cl)->value){
  2777.             ekey[0].ch    = ctrl('W');
  2778.             ekey[0].rval  = 5;
  2779.             ekey[0].name  = "^W";
  2780.             ekey[0].label = after ? "InsertBefore" : "InsertAfter";
  2781.             ekey[1].ch    = -1;
  2782.         }
  2783.         else if(!(flags&CF_NUMBER))
  2784.           ekey[0].ch    = -1;
  2785.  
  2786.         i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  2787.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  2788.         if(i == 0){
  2789.             rv = ps->mangled_body = 1;
  2790.             removing_leading_white_space(sval);
  2791.             removing_trailing_white_space(sval);
  2792.             /*
  2793.              * Coerce "" and <Empty Value> to empty string input.
  2794.              * Catch <No Value Set> as a substitute for deleting.
  2795.              */
  2796.             if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
  2797.                 || !struncmp(sval, empty_val, EMPTY_VAL_LEN) 
  2798.             || (*sval == '<'
  2799.                 && !struncmp(sval+1, empty_val, EMPTY_VAL_LEN)))
  2800.               *sval = '\0';
  2801.             else if(!struncmp(sval, no_val, NO_VAL_LEN)
  2802.                 || (*sval == '<'
  2803.                 && !struncmp(sval+1, no_val, NO_VAL_LEN)))
  2804.               goto delete;
  2805.  
  2806.             if((*cl)->var->is_list){
  2807.             if(*sval || !(*cl)->var->user_val.l){
  2808.                 char **ltmp;
  2809.                 int    i;
  2810.  
  2811.                 i = 0;
  2812.                 for(tmp = sval; *tmp; tmp++)
  2813.                   if(*tmp == ',')
  2814.                 i++;    /* conservative count of ,'s */
  2815.  
  2816.                 if(!i){
  2817.                 ltmp    = (char **)fs_get(2 * sizeof(char *));
  2818.                 ltmp[0] = cpystr(sval);
  2819.                 ltmp[1] = NULL;
  2820.                 }
  2821.                 else
  2822.                   ltmp = parse_list(sval, i + 1, NULL);
  2823.  
  2824.                 if(ltmp[0]){
  2825.                 config_add_list(ps, cl, ltmp, &newval, after);
  2826.                 if(after)
  2827.                   skip_to_next = 1;
  2828.                 }
  2829.                 else{
  2830.                 q_status_message1(SM_ORDER, 0, 3,
  2831.                      "Can't add %s to list", empty_val);
  2832.                 rv = ps->mangled_body = 0;
  2833.                 }
  2834.  
  2835.                 fs_give((void **)<mp);
  2836.             }
  2837.             else{
  2838.                 q_status_message1(SM_ORDER, 0, 3,
  2839.                      "Can't add %s to list", empty_val);
  2840.             }
  2841.             }
  2842.             else{
  2843.             if(flags&CF_NUMBER && sval[0]
  2844.               && !(isdigit((unsigned char)sval[0])
  2845.                    || sval[0] == '-' || sval[0] == '+')){
  2846.                 q_status_message(SM_ORDER,3,3,
  2847.                   "Entry must be numeric");
  2848.                 i = 3; /* to keep loop going */
  2849.                 continue;
  2850.             }
  2851.  
  2852.             if((*cl)->var->user_val.p)
  2853.               fs_give((void **)&(*cl)->var->user_val.p);
  2854.  
  2855.             (*cl)->var->user_val.p = cpystr(sval);
  2856.             newval = &(*cl)->value;
  2857.             }
  2858.         }
  2859.         else if(i == 1){
  2860.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  2861.         }
  2862.         else if(i == 3){
  2863.             help = help == NO_HELP ? h_config_add : NO_HELP;
  2864.             continue;
  2865.         }
  2866.         else if(i == 4){        /* no redraw, yet */
  2867.             continue;
  2868.         }
  2869.         else if(i == 5){ /* change from/to prepend to/from append */
  2870.             char tmpval[101];
  2871.  
  2872.             after = after ? 0 : 1;
  2873.             strncpy(tmpval, (*cl)->value, 100);
  2874.             removing_trailing_white_space(tmpval);
  2875.             /* 33 is the number of chars other than the value */
  2876.             k = min(18, max(maxwidth-33,0));
  2877.             if(strlen(tmpval) > k && k >= 3){
  2878.             tmpval[k-1] = tmpval[k-2] = tmpval[k-3] = '.';
  2879.             tmpval[k] = '\0';
  2880.             }
  2881.  
  2882.             sprintf(prompt,
  2883.             "Enter text to insert %s \"%.*s\": ",
  2884.             after ? "after" : "before", k, tmpval);
  2885.             continue;
  2886.         }
  2887.         else if(i == ctrl('P')){
  2888.             if(sval[0])
  2889.               numval = atoi(sval);
  2890.             else{
  2891.               if((*cl)->var->current_val.p)
  2892.             numval = atoi((*cl)->var->current_val.p);
  2893.               else
  2894.             numval = lowrange + 1;
  2895.             }
  2896.  
  2897.             if(numval == lowrange){
  2898.             /*
  2899.              * Protect user from repeating arrow key that
  2900.              * causes message to appear over and over.
  2901.              */
  2902.             if(++repeat_key > 0){
  2903.                 q_status_message1(SM_ORDER,3,3,
  2904.                 "Minimum value is %s", comatose(lowrange));
  2905.                 repeat_key = -5;
  2906.             }
  2907.             }
  2908.             else
  2909.               repeat_key = 0;
  2910.  
  2911.             numval = max(numval - incr, lowrange);
  2912.             sprintf(sval, "%d", numval);
  2913.             continue;
  2914.         }
  2915.         else if(i == ctrl('N')){
  2916.             if(sval[0])
  2917.               numval = atoi(sval);
  2918.             else{
  2919.               if((*cl)->var->current_val.p)
  2920.             numval = atoi((*cl)->var->current_val.p);
  2921.               else
  2922.             numval = lowrange + 1;
  2923.             }
  2924.  
  2925.             if(numval == hirange){
  2926.             if(++repeat_key > 0){
  2927.                 q_status_message1(SM_ORDER,3,3,
  2928.                 "Maximum value is %s", comatose(hirange));
  2929.                 repeat_key = -5;
  2930.             }
  2931.             }
  2932.             else
  2933.               repeat_key = 0;
  2934.  
  2935.             numval = min(numval + incr, hirange);
  2936.             sprintf(sval, "%d", numval);
  2937.             continue;
  2938.         }
  2939.  
  2940.         break;
  2941.         }
  2942.     }
  2943.  
  2944.     break;
  2945.  
  2946.       case 'd' :                /* delete */
  2947.       case PF10 :
  2948. delete:
  2949.     if(!(*cl)->var->is_list
  2950.         && !(*cl)->var->user_val.p
  2951.         && (*cl)->var->current_val.p){
  2952.         char pmt[40];
  2953.  
  2954.         sprintf(pmt, "Override default with %s", empty_val2);
  2955.         if(want_to(pmt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  2956.         sval[0] = '\0';
  2957.         (*cl)->var->user_val.p = cpystr(sval);
  2958.         newval = &(*cl)->value;
  2959.         rv = ps->mangled_body = 1;
  2960.         }
  2961.     }
  2962.     else if((*cl)->var->is_list
  2963.         && !(*cl)->var->user_val.l
  2964.         && (*cl)->var->current_val.l){
  2965.         char pmt[40];
  2966.  
  2967.         sprintf(pmt, "Override default with %s", empty_val2);
  2968.         if(want_to(pmt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  2969.         char **ltmp;
  2970.  
  2971.         sval[0] = '\0';
  2972.         ltmp    = (char **)fs_get(2 * sizeof(char *));
  2973.         ltmp[0] = cpystr(sval);
  2974.         ltmp[1] = NULL;
  2975.         config_add_list(ps, cl, ltmp, &newval, 0);
  2976.         fs_give((void **)<mp);
  2977.         rv = ps->mangled_body = 1;
  2978.         }
  2979.     }
  2980.     else if(((*cl)->var->is_list && !(*cl)->var->user_val.l)
  2981.         || (!(*cl)->var->is_list && !(*cl)->var->user_val.p)){
  2982.         q_status_message(SM_ORDER, 0, 3, "No set value to delete");
  2983.     }
  2984.     else{
  2985.         if((*cl)->var->is_fixed)
  2986.             sprintf(prompt, "Delete (unused) %.30s from %.20s ",
  2987.             (*cl)->var->is_list
  2988.               ? (!*(*cl)->var->user_val.l[(*cl)->varmem])
  2989.               ? empty_val2
  2990.               : (*cl)->var->user_val.l[(*cl)->varmem]
  2991.               : ((*cl)->var->user_val.p)
  2992.               ? (!*(*cl)->var->user_val.p)
  2993.                   ? empty_val2
  2994.                   : (*cl)->var->user_val.p
  2995.                : "<NULL VALUE>",
  2996.             (*cl)->var->name);
  2997.         else
  2998.             sprintf(prompt, "Really delete %s%.20s from %.30s ",
  2999.             (*cl)->var->is_list ? "item " : "", 
  3000.             (*cl)->var->is_list
  3001.               ? int2string((*cl)->varmem + 1)
  3002.               : ((*cl)->var->user_val.p)
  3003.               ? (!*(*cl)->var->user_val.p)
  3004.                   ? empty_val2
  3005.                   : (*cl)->var->user_val.p
  3006.                : "<NULL VALUE>",
  3007.             (*cl)->var->name);
  3008.  
  3009.         ps->mangled_footer = 1;
  3010.         if(want_to(prompt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  3011.         rv = ps->mangled_body = 1;
  3012.         if((*cl)->var->is_list){
  3013.             fs_give((void **)&(*cl)->var->user_val.l[(*cl)->varmem]);
  3014.             config_del_list_item(cl, &newval);
  3015.         }
  3016.         else{
  3017.             fs_give((void **)&(*cl)->var->user_val.p);
  3018.             newval = &(*cl)->value;
  3019.         }
  3020.         }
  3021.         else
  3022.           q_status_message(SM_ORDER, 0, 3, "Value not deleted");
  3023.     }
  3024.  
  3025.     break;
  3026.  
  3027.       case ctrl('M') :
  3028.       case ctrl('J') :
  3029.       case 'c' :                /* edit/change list option */
  3030.       case PF4 :
  3031.     if((*cl)->var->is_fixed){
  3032.         q_status_message(SM_ORDER, 3, 3,
  3033.                  "Can't change sys-admin defined value.");
  3034.     }
  3035.     else if(((*cl)->var->is_list
  3036.             && !(*cl)->var->user_val.l
  3037.             && (*cl)->var->current_val.l)
  3038.         ||
  3039.         (!(*cl)->var->is_list
  3040.             && !(*cl)->var->user_val.p
  3041.             && (*cl)->var->current_val.p)){
  3042.         goto replace_text;
  3043.     }
  3044.     else if(((*cl)->var->is_list
  3045.             && !(*cl)->var->user_val.l
  3046.             && !(*cl)->var->current_val.l)
  3047.         ||
  3048.         (!(*cl)->var->is_list
  3049.             && !(*cl)->var->user_val.p
  3050.             && !(*cl)->var->current_val.p)){
  3051.         goto add_text;
  3052.     }
  3053.     else{
  3054.         HelpType help;
  3055.  
  3056.         if((*cl)->var->is_list){
  3057.         sprintf(prompt, "Change field %.30s list entry : ",
  3058.             (*cl)->var->name);
  3059.         sprintf(sval, "%s",
  3060.             (*cl)->var->user_val.l[(*cl)->varmem]
  3061.               ? (*cl)->var->user_val.l[(*cl)->varmem] : "");
  3062.         }
  3063.         else{
  3064.         sprintf(prompt, "Change %sfield %.35s value : ",
  3065.             flags&CF_NUMBER ? "numeric " : "",
  3066.             (*cl)->var->name);
  3067.         sprintf(sval, "%s", (*cl)->var->user_val.p
  3068.                      ? (*cl)->var->user_val.p : "");
  3069.         }
  3070.  
  3071.         ps->mangled_footer = 1;
  3072.         help = NO_HELP;
  3073.         while(1){
  3074.         if(!(flags&CF_NUMBER))
  3075.           ekey[0].ch = -1;
  3076.  
  3077.         i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  3078.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  3079.         if(i == 0){
  3080.             removing_leading_white_space(sval);
  3081.             removing_trailing_white_space(sval);
  3082.             /*
  3083.              * Coerce "" and <Empty Value> to empty string input.
  3084.              * Catch <No Value Set> as a substitute for deleting.
  3085.              */
  3086.             if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
  3087.                 || !struncmp(sval, empty_val, EMPTY_VAL_LEN) 
  3088.             || (*sval == '<'
  3089.                 && !struncmp(sval+1, empty_val, EMPTY_VAL_LEN)))
  3090.               *sval = '\0';
  3091.             else if(!struncmp(sval, no_val, NO_VAL_LEN)
  3092.             || (*sval == '<'
  3093.                 && !struncmp(sval+1, no_val, NO_VAL_LEN)))
  3094.               goto delete;
  3095.  
  3096.             rv = ps->mangled_body = 1;
  3097.             if((*cl)->var->is_list){
  3098.             char **ltmp = NULL;
  3099.             int    i;
  3100.  
  3101.             if((*cl)->var->user_val.l[(*cl)->varmem])
  3102.               fs_give((void **)&(*cl)->var->user_val.l[
  3103.                                    (*cl)->varmem]);
  3104.  
  3105.             i = 0;
  3106.             for(tmp = sval; *tmp; tmp++)
  3107.               if(*tmp == ',')
  3108.                 i++;    /* conservative count of ,'s */
  3109.  
  3110.             if(i)
  3111.               ltmp = parse_list(sval, i + 1, NULL);
  3112.  
  3113.             if(!i || (ltmp && !ltmp[1])){    /* only one item */
  3114.                 (*cl)->var->user_val.l[(*cl)->varmem] =
  3115.                                   cpystr(sval);
  3116.                 newval = &(*cl)->value;
  3117.  
  3118.                 if(ltmp && ltmp[0])
  3119.                   fs_give((void **)<mp[0]);
  3120.             }
  3121.             else if(ltmp){
  3122.                 /*
  3123.                  * Looks like the value was changed to a 
  3124.                  * list, so delete old value, and insert
  3125.                  * new list...
  3126.                  *
  3127.                  * If more than one item in existing list and
  3128.                  * current is end of existing list, then we
  3129.                  * have to delete and append instead of
  3130.                  * deleting and prepending.
  3131.                  */
  3132.                 if(((*cl)->varmem > 0 || (*cl)->var->user_val.l[1])
  3133.                    && !((*cl)->var->user_val.l[(*cl)->varmem+1])){
  3134.                 after = 1;
  3135.                 skip_to_next = 1;
  3136.                 }
  3137.  
  3138.                 config_del_list_item(cl, &newval);
  3139.                 config_add_list(ps, cl, ltmp, &newval, after);
  3140.             }
  3141.  
  3142.             if(ltmp)
  3143.               fs_give((void **)<mp);
  3144.             }
  3145.             else{
  3146.             if(flags&CF_NUMBER && sval[0]
  3147.               && !(isdigit((unsigned char)sval[0])
  3148.                    || sval[0] == '-' || sval[0] == '+')){
  3149.                 q_status_message(SM_ORDER,3,3,
  3150.                   "Entry must be numeric");
  3151.                 continue;
  3152.             }
  3153.  
  3154.             if((*cl)->var->user_val.p)
  3155.               fs_give((void **)&(*cl)->var->user_val.p);
  3156.  
  3157.             if(sval[0])
  3158.               (*cl)->var->user_val.p = cpystr(sval);
  3159.  
  3160.             newval = &(*cl)->value;
  3161.             }
  3162.         }
  3163.         else if(i == 1){
  3164.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  3165.         }
  3166.         else if(i == 3){
  3167.             help = help == NO_HELP ? h_config_change : NO_HELP;
  3168.             continue;
  3169.         }
  3170.         else if(i == 4){        /* no redraw, yet */
  3171.             continue;
  3172.         }
  3173.         else if(i == ctrl('P')){
  3174.             numval = atoi(sval);
  3175.             if(numval == lowrange){
  3176.             /*
  3177.              * Protect user from repeating arrow key that
  3178.              * causes message to appear over and over.
  3179.              */
  3180.             if(++repeat_key > 0){
  3181.                 q_status_message1(SM_ORDER,3,3,
  3182.                 "Minimum value is %s", comatose(lowrange));
  3183.                 repeat_key = -5;
  3184.             }
  3185.             }
  3186.             else
  3187.               repeat_key = 0;
  3188.  
  3189.             numval = max(numval - incr, lowrange);
  3190.             sprintf(sval, "%d", numval);
  3191.             continue;
  3192.         }
  3193.         else if(i == ctrl('N')){
  3194.             numval = atoi(sval);
  3195.             if(numval == hirange){
  3196.             if(++repeat_key > 0){
  3197.                 q_status_message1(SM_ORDER,3,3,
  3198.                 "Maximum value is %s", comatose(hirange));
  3199.                 repeat_key = -5;
  3200.             }
  3201.             }
  3202.             else
  3203.               repeat_key = 0;
  3204.  
  3205.             numval = min(numval + incr, hirange);
  3206.             sprintf(sval, "%d", numval);
  3207.             continue;
  3208.         }
  3209.  
  3210.         break;
  3211.         }
  3212.     }
  3213.  
  3214.     break;
  3215.  
  3216.       case 'e' :                /* exit */
  3217.       case PF3 :
  3218.     rv = config_exit_cmd(flags);
  3219.     break;
  3220.  
  3221.       default :
  3222.     rv = -1;
  3223.     break;
  3224.     }
  3225.  
  3226.     if(skip_to_next)
  3227.       *cl = next_confline(*cl);
  3228.  
  3229.     /*
  3230.      * At this point, if changes occurred, var->user_val.X is set.
  3231.      * So, fix the current_val, and handle special cases...
  3232.      *
  3233.      * NOTE: we don't worry about the "fixed variable" case here, because
  3234.      *       editing such vars should have been prevented above...
  3235.      */
  3236.     if(rv == 1){
  3237.     /*
  3238.      * Now go and set the current_val based on user_val changes
  3239.      * above.  Turn off command line settings...
  3240.      */
  3241.     set_current_val((*cl)->var, TRUE, FALSE);
  3242.     fix_side_effects(ps, (*cl)->var, 0);
  3243.  
  3244.     /*
  3245.      * Delay setting the displayed value until "var.current_val" is set
  3246.      * in case current val get's changed due to a special case above.
  3247.      */
  3248.     if(newval){
  3249.         if(*newval)
  3250.           fs_give((void **)newval);
  3251.  
  3252.         *newval = pretty_value(ps, *cl);
  3253.     }
  3254.     }
  3255.  
  3256.     return(rv);
  3257. }
  3258.  
  3259.  
  3260. int
  3261. config_exit_cmd(flags)
  3262.     unsigned flags;
  3263. {
  3264.     return(screen_exit_cmd(flags, "Configuration"));
  3265. }
  3266.  
  3267.  
  3268. flag_exit_cmd(flags)
  3269.     unsigned flags;
  3270. {
  3271.     return(2);
  3272. }
  3273.  
  3274.  
  3275. /*
  3276.  * screen_exit_cmd - basic config/flag screen exit logic
  3277.  */
  3278. int
  3279. screen_exit_cmd(flags, cmd)
  3280.     unsigned  flags;
  3281.     char     *cmd;
  3282. {
  3283.     if(flags & CF_CHANGES){
  3284.       switch(want_to(EXIT_PMT, 'y', 'x', h_config_undo, 0, 1)){
  3285.     case 'y':
  3286.       q_status_message1(SM_ORDER,0,3,"%s changes saved", cmd);
  3287.       return(2);
  3288.  
  3289.     case 'n':
  3290.       q_status_message1(SM_ORDER,3,5,"No %s changes saved", cmd);
  3291.       return(10);
  3292.  
  3293.     case 'x':  /* ^C */
  3294.       q_status_message(SM_ORDER,3,5,"Changes not yet saved");
  3295.       return(0);
  3296.       }
  3297.     }
  3298.     else
  3299.       return(2);
  3300. }
  3301.  
  3302.  
  3303. /*
  3304.  *
  3305.  */
  3306. void
  3307. config_add_list(ps, cl, ltmp, newval, after)
  3308.     struct pine *ps;
  3309.     CONF_S     **cl;
  3310.     char       **ltmp, ***newval;
  3311.     int         after;
  3312. {
  3313.     int        items, i;
  3314.     char   *tmp;
  3315.     CONF_S *ctmp;
  3316.  
  3317.     for(items = 0, i = 0; ltmp[i]; i++)        /* count list items */
  3318.       items++;
  3319.  
  3320.     if((*cl)->var->user_val.l){
  3321.     if((*cl)->var->user_val.l[0]
  3322.        && (*cl)->var->user_val.l[0][0]){
  3323.         /*
  3324.          * Since we were already a list, make room
  3325.          * for the new member[s] and fall thru to
  3326.          * actually fill them in below...
  3327.          */
  3328.         for(i = 0; (*cl)->var->user_val.l[i]; i++)
  3329.           ;
  3330.  
  3331.         fs_resize((void **)&(*cl)->var->user_val.l,
  3332.               (i + items + 1) * sizeof(char *));
  3333.         /*
  3334.          * move the ones that will be bumped down to the bottom of the list
  3335.          */
  3336.         for(; i >= (*cl)->varmem + (after?1:0); i--)
  3337.           (*cl)->var->user_val.l[i+items] =
  3338.         (*cl)->var->user_val.l[i];
  3339.  
  3340.         i = 0;
  3341.     }
  3342.     else{
  3343.         (*cl)->varmem = 0;
  3344.         if((*cl)->var->user_val.l[0])
  3345.           fs_give((void **)&(*cl)->var->user_val.l[0]);
  3346.  
  3347.         (*cl)->var->user_val.l[0] = ltmp[0];
  3348.         *newval = &(*cl)->value;
  3349.         if((*cl)->value)
  3350.           fs_give((void **)&(*cl)->value);
  3351.  
  3352.         i = 1;
  3353.     }
  3354.     }
  3355.     else{
  3356.     /*
  3357.      * since we were previously empty, we want
  3358.      * to replace the first CONF_S's value with
  3359.      * the first new value, and fill the other
  3360.      * in below if there's a list...
  3361.      */
  3362.     (*cl)->var->user_val.l = (char **)fs_get((items+1)*sizeof(char *));
  3363.     memset((void *)(*cl)->var->user_val.l, 0, (items+1) * sizeof(char *));
  3364.     (*cl)->var->user_val.l[(*cl)->varmem=0] = ltmp[0];
  3365.     *newval = &(*cl)->value;
  3366.     if((*cl)->value)
  3367.       fs_give((void **)&(*cl)->value);
  3368.  
  3369.     i = 1;
  3370.     }
  3371.  
  3372.     /*
  3373.      * Make new cl's to fit in the new space.  Move the value from the current
  3374.      * line if inserting before it, else leave it where it is.
  3375.      */
  3376.     for(; i < items ; i++){
  3377.     (*cl)->var->user_val.l[i+(*cl)->varmem + (after?1:0)] = ltmp[i];
  3378.     tmp = (*cl)->value;
  3379.     new_confline(cl);
  3380.     if(after)
  3381.       (*cl)->value   = NULL;
  3382.     else
  3383.       (*cl)->value   = tmp;
  3384.  
  3385.     (*cl)->var       = (*cl)->prev->var;
  3386.     (*cl)->valoffset = (*cl)->prev->valoffset;
  3387.     (*cl)->varoffset = (*cl)->prev->varoffset;
  3388.     (*cl)->headingp  = (*cl)->prev->headingp;
  3389.     (*cl)->keymenu   = (*cl)->prev->keymenu;
  3390.     (*cl)->help      = (*cl)->prev->help;
  3391.     (*cl)->tool      = (*cl)->prev->tool;
  3392.     (*cl)->varnamep  = (*cl)->prev->varnamep;
  3393.     *cl         = (*cl)->prev;
  3394.     if(!after)
  3395.       (*cl)->value   = NULL;
  3396.  
  3397.     if(after)
  3398.       *newval     = &(*cl)->next->value;
  3399.     else
  3400.       *newval     = &(*cl)->value;
  3401.     }
  3402.  
  3403.     /*
  3404.      * now fix up varmem values and fill in new values that have been
  3405.      * left NULL
  3406.      */
  3407.     for(ctmp = (*cl)->varnamep, i = 0;
  3408.     (*cl)->var->user_val.l[i];
  3409.     ctmp = ctmp->next, i++){
  3410.     ctmp->varmem = i;
  3411.     if(!ctmp->value)
  3412.       ctmp->value = pretty_value(ps, ctmp);
  3413.     }
  3414. }
  3415.  
  3416.  
  3417. /*
  3418.  *
  3419.  */
  3420. void
  3421. config_del_list_item(cl, newval)
  3422.     CONF_S  **cl;
  3423.     char   ***newval;
  3424. {
  3425.     char   **bufp;
  3426.     int         i;
  3427.     CONF_S  *ctmp;
  3428.  
  3429.     if((*cl)->var->user_val.l[(*cl)->varmem + 1]){
  3430.     for(bufp = &(*cl)->var->user_val.l[(*cl)->varmem];
  3431.         *bufp = *(bufp+1); bufp++)
  3432.       ;
  3433.  
  3434.     if(*cl == (*cl)->varnamep){        /* leading value */
  3435.         if((*cl)->value)
  3436.           fs_give((void **)&(*cl)->value);
  3437.  
  3438.         ctmp = (*cl)->next;
  3439.         (*cl)->value = ctmp->value;
  3440.         ctmp->value  = NULL;
  3441.     }
  3442.     else{
  3443.         ctmp = *cl;            /* blast the confline */
  3444.         *cl = (*cl)->next;
  3445.         if(ctmp == opt_screen->top_line)
  3446.           opt_screen->top_line = *cl;
  3447.     }
  3448.  
  3449.     free_confline(&ctmp);
  3450.  
  3451.     for(ctmp = (*cl)->varnamep, i = 0;    /* now fix up varmem values */
  3452.         (*cl)->var->user_val.l[i];
  3453.         ctmp = ctmp->next, i++)
  3454.       ctmp->varmem = i;
  3455.     }
  3456.     else if((*cl)->varmem){            /* blasted last in list */
  3457.     ctmp = *cl;
  3458.     *cl = (*cl)->prev;
  3459.     if(ctmp == opt_screen->top_line)
  3460.       opt_screen->top_line = *cl;
  3461.  
  3462.     free_confline(&ctmp);
  3463.     }
  3464.     else{                    /* blasted last remaining */
  3465.     fs_give((void **)&(*cl)->var->user_val.l);
  3466.     *newval = &(*cl)->value;
  3467.     }
  3468. }
  3469.  
  3470.  
  3471. /*
  3472.  * feature list manipulation tool
  3473.  * 
  3474.  * 
  3475.  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
  3476.  */
  3477. int
  3478. checkbox_tool(ps, cmd, cl, flags)
  3479.     struct pine  *ps;
  3480.     int          cmd;
  3481.     CONF_S    **cl;
  3482.     unsigned      flags;
  3483. {
  3484.     int  rv = 0;
  3485.  
  3486.     switch(cmd){
  3487.       case ctrl('M') :
  3488.       case ctrl('J') :
  3489.       case 'x' :                /* mark/unmark feature */
  3490.       case PF4 :
  3491.     if((*cl)->var == &ps->vars[V_FEATURE_LIST]){
  3492.         rv = 1;
  3493.         toggle_feature_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value);
  3494.     }
  3495.     else
  3496.       q_status_message(SM_ORDER | SM_DING, 3, 6,
  3497.                "Programmer botch!  Unknown checkbox type.");
  3498.  
  3499.     break;
  3500.  
  3501.       case 'e' :                /* exit */
  3502.       case PF3 :
  3503.     rv = config_exit_cmd(flags);
  3504.     break;
  3505.  
  3506.       default :
  3507.     rv = -1;
  3508.     break;
  3509.     }
  3510.  
  3511.     return(rv);
  3512. }
  3513.  
  3514.  
  3515. /*
  3516.  * Message flag manipulation tool
  3517.  * 
  3518.  * 
  3519.  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
  3520.  */
  3521. int
  3522. flag_checkbox_tool(ps, cmd, cl, flags)
  3523.     struct pine  *ps;
  3524.     int          cmd;
  3525.     CONF_S    **cl;
  3526.     unsigned      flags;
  3527. {
  3528.     int  rv = 0, state;
  3529.  
  3530.     switch(cmd){
  3531.       case ctrl('M') :
  3532.       case ctrl('J') :
  3533.       case 'x' :                /* mark/unmark feature */
  3534.       case PF4 :
  3535.     state = ((struct flag_table *)(*cl)->scrap)->set;
  3536.     state = (state == 1)
  3537.           ? 0
  3538.           : (state == 0 && (((struct flag_table *)(*cl)->scrap)->ukn))
  3539.               ? 2 : 1;
  3540.     (*cl)->value[1] = (state == 0) ? ' ' : ((state == 1) ? 'X': '?');
  3541.     ((struct flag_table *)(*cl)->scrap)->set = state;
  3542.     rv = 1;
  3543.     break;
  3544.  
  3545.       case 'e' :                /* exit */
  3546.       case PF3 :
  3547.     rv = flag_exit_cmd(flags);
  3548.     break;
  3549.  
  3550.       default :
  3551.     rv = -1;
  3552.     break;
  3553.     }
  3554.  
  3555.     return(rv);
  3556. }
  3557.  
  3558.  
  3559. /*
  3560.  * simple radio-button style variable handler
  3561.  */
  3562. int
  3563. radiobutton_tool(ps, cmd, cl, flags)
  3564.     struct pine  *ps;
  3565.     int              cmd;
  3566.     CONF_S      **cl;
  3567.     unsigned      flags;
  3568. {
  3569.     int           rv = 0;
  3570.     CONF_S    *ctmp;
  3571.  
  3572.     if((*cl)->var->is_fixed
  3573.        && (cmd == ctrl('M') || cmd == ctrl('J') || cmd == '*' || cmd == PF4)){
  3574.     q_status_message(SM_ORDER, 3, 3,
  3575.              "Can't change sys-admin defined value.");
  3576.     if((*cl)->var->user_val.p){
  3577.         if(want_to("Delete old unused personal option setting", 'y', 'n',
  3578.                 NO_HELP, 0, 1) == 'y'){
  3579.         fs_give((void **)&(*cl)->var->user_val.p);
  3580.         q_status_message(SM_ORDER, 0, 3, "Deleted");
  3581.         rv = 1;
  3582.         }
  3583.     }
  3584.     return(rv);
  3585.     }
  3586.  
  3587.     switch(cmd){
  3588.       case ctrl('M') :
  3589.       case ctrl('J') :
  3590.       case '*' :                /* set/unset feature */
  3591.       case PF4 :
  3592.     /* hunt backwards, turning off old values */
  3593.     for(ctmp = *cl; ctmp && !(ctmp->flags & CF_NOSELECT) && !ctmp->varname;
  3594.         ctmp = prev_confline(ctmp))
  3595.       ctmp->value[1] = ' ';
  3596.  
  3597.     /* hunt forwards, turning off old values */
  3598.     for(ctmp = *cl; ctmp && !ctmp->varname; ctmp = next_confline(ctmp))
  3599.       ctmp->value[1] = ' ';
  3600.  
  3601.     /* turn on current value */
  3602.     (*cl)->value[1] = R_SELD;
  3603.  
  3604.     if((*cl)->var == &ps->vars[V_SAVED_MSG_NAME_RULE]
  3605.        || (*cl)->var == &ps->vars[V_FCC_RULE]
  3606.        || (*cl)->var == &ps->vars[V_GOTO_DEFAULT_RULE]
  3607.        || (*cl)->var == &ps->vars[V_AB_SORT_RULE]){
  3608.         NAMEVAL_S *rule;
  3609.  
  3610.         if((*cl)->var == &ps->vars[V_SAVED_MSG_NAME_RULE]){
  3611.         rule          = save_msg_rules((*cl)->varmem);
  3612.         ps->save_msg_rule = rule->value;
  3613.         }
  3614.         else if((*cl)->var == &ps->vars[V_FCC_RULE]){
  3615.         rule         = fcc_rules((*cl)->varmem);
  3616.         ps->fcc_rule = rule->value;
  3617.         }
  3618.         else if((*cl)->var == &ps->vars[V_GOTO_DEFAULT_RULE]){
  3619.         rule              = goto_rules((*cl)->varmem);
  3620.         ps->goto_default_rule = rule->value;
  3621.         }
  3622.         else{
  3623.         rule             = ab_sort_rules((*cl)->varmem);
  3624.         ps->ab_sort_rule = rule->value;
  3625.         addrbook_reset();
  3626.         }
  3627.  
  3628.         if((*cl)->var->user_val.p)
  3629.           fs_give((void **)&(*cl)->var->user_val.p);
  3630.  
  3631.         (*cl)->var->user_val.p = cpystr(rule->name);
  3632.  
  3633.         ps->mangled_body = 1;    /* BUG: redraw it all for now? */
  3634.         rv = 1;
  3635.     }
  3636.     else if((*cl)->var == &ps->vars[V_SORT_KEY]){
  3637.         ps->def_sort_rev  = (*cl)->varmem >= (short) EndofList;
  3638.         ps->def_sort      = (SortOrder) ((*cl)->varmem - (ps->def_sort_rev
  3639.                                  * EndofList));
  3640.         if((*cl)->var->user_val.p)
  3641.           fs_give((void **)&(*cl)->var->user_val.p);
  3642.  
  3643.         sprintf(tmp_20k_buf, "%s%s%s", sort_name(ps->def_sort),
  3644.             (ps->def_sort_rev) ? "/" : "",
  3645.             (ps->def_sort_rev) ? "Reverse" : "");
  3646.  
  3647.         (*cl)->var->user_val.p = cpystr(tmp_20k_buf);
  3648.  
  3649.         ps->mangled_body = 1;    /* BUG: redraw it all for now? */
  3650.         rv = 1;
  3651.     }
  3652. #if defined(DOS) || defined(OS2)
  3653.     else if((*cl)->var == &ps->vars[V_NORM_FORE_COLOR]
  3654.         || (*cl)->var == &ps->vars[V_NORM_BACK_COLOR]
  3655.         || (*cl)->var == &ps->vars[V_REV_FORE_COLOR]
  3656.         || (*cl)->var == &ps->vars[V_REV_BACK_COLOR]){
  3657.         if((*cl)->var->user_val.p)
  3658.           fs_give((void **)&(*cl)->var->user_val.p);
  3659.  
  3660.         (*cl)->var->user_val.p = cpystr(config_colors[(*cl)->varmem]);
  3661.  
  3662.         if((*cl)->var == &ps->vars[V_NORM_FORE_COLOR])
  3663.           pico_nfcolor((*cl)->var->user_val.p);
  3664.         else if((*cl)->var == &ps->vars[V_NORM_BACK_COLOR])
  3665.           pico_nbcolor((*cl)->var->user_val.p);
  3666.         else if((*cl)->var == &ps->vars[V_REV_FORE_COLOR])
  3667.           pico_rfcolor((*cl)->var->user_val.p);
  3668.         else
  3669.           pico_rbcolor((*cl)->var->user_val.p);
  3670.         
  3671.         ps->mangled_screen = 1;
  3672.         rv = 1;
  3673.     }
  3674. #endif
  3675.     else
  3676.       q_status_message(SM_ORDER | SM_DING, 3, 6,
  3677.                "Programmer botch!  Unknown radiobutton type.");
  3678.  
  3679.     break;
  3680.  
  3681.       case 'e' :                /* exit */
  3682.       case PF3 :
  3683.     rv = config_exit_cmd(flags);
  3684.     break;
  3685.  
  3686.       default :
  3687.     rv = -1;
  3688.     break;
  3689.     }
  3690.  
  3691.     return(rv);
  3692. }
  3693.  
  3694.  
  3695.  
  3696. /*
  3697.  * simple yes/no style variable handler
  3698.  */
  3699. int
  3700. yesno_tool(ps, cmd, cl, flags)
  3701.     struct pine  *ps;
  3702.     int              cmd;
  3703.     CONF_S      **cl;
  3704.     unsigned      flags;
  3705. {
  3706.     int  rv = 0;
  3707.  
  3708.     if((*cl)->var->is_fixed
  3709.        && (cmd == ctrl('M') || cmd == ctrl('J') || cmd == 'c' || cmd == PF4)){
  3710.     q_status_message(SM_ORDER, 3, 3,
  3711.              "Can't change sys-admin defined value.");
  3712.     if((*cl)->var->user_val.p){
  3713.         if(want_to("Delete old unused personal option setting", 'y', 'n',
  3714.                 NO_HELP, 0, 1) == 'y'){
  3715.         fs_give((void **)&(*cl)->var->user_val.p);
  3716.         q_status_message(SM_ORDER, 0, 3, "Deleted");
  3717.         rv = 1;
  3718.         }
  3719.     }
  3720.     return(rv);
  3721.     }
  3722.  
  3723.     switch(cmd){
  3724.       case ctrl('M') :
  3725.       case ctrl('J') :
  3726.       case 'c' :                /* toggle yes to no and back */
  3727.       case PF4 :
  3728.     rv = 1;
  3729.     fs_give((void **)&(*cl)->value);
  3730.     if((*cl)->var->user_val.p)
  3731.       fs_give((void **)&(*cl)->var->user_val.p);
  3732.  
  3733.     if((*cl)->var->user_val.p && !strucmp((*cl)->var->user_val.p, "yes")
  3734.        || (!(*cl)->var->user_val.p && (*cl)->var->current_val.p
  3735.            && !strucmp((*cl)->var->current_val.p, "yes")))
  3736.       (*cl)->var->user_val.p = cpystr("No");
  3737.     else
  3738.       (*cl)->var->user_val.p = cpystr("Yes");
  3739.  
  3740.     sprintf(tmp_20k_buf, "%-*s", ps->ttyo->screen_cols - (*cl)->valoffset,
  3741.         (*cl)->var->user_val.p);
  3742.  
  3743.     (*cl)->value = cpystr(tmp_20k_buf);
  3744.  
  3745.     if((*cl)->var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
  3746.         set_current_val((*cl)->var, FALSE, FALSE);
  3747.         init_hostname(ps);
  3748.     }
  3749.  
  3750.     break;
  3751.  
  3752.       case 'e' :                /* exit */
  3753.       case PF3 :
  3754.     rv = config_exit_cmd(flags);
  3755.     break;
  3756.  
  3757.       default :
  3758.     rv = -1;
  3759.     break;
  3760.     }
  3761.  
  3762.     return(rv);
  3763. }
  3764.  
  3765.  
  3766. int
  3767. print_select_tool(ps, cmd, cl, flags)
  3768.     struct pine *ps;
  3769.     int          cmd;
  3770.     CONF_S     **cl;
  3771.     unsigned     flags;
  3772. {
  3773.     int rc, i, retval;
  3774.     char *p;
  3775.     struct variable *vtmp;
  3776.  
  3777.     switch(cmd){
  3778.       case 'e':
  3779.       case PF3:
  3780.         retval = config_exit_cmd(flags);
  3781.     break;
  3782.  
  3783.       case 's':
  3784.       case PF4:
  3785.       case ctrl('M'):
  3786.       case ctrl('J'):
  3787.     if(cl && *cl){
  3788.         if((*cl)->var){
  3789.         vtmp = (*cl)->var;
  3790.         i = vtmp->current_val.l
  3791.             && vtmp->current_val.l[(*cl)->varmem]
  3792.             && vtmp->current_val.l[(*cl)->varmem][0];
  3793.         rc = set_variable(V_PRINTER,
  3794.             vtmp->current_val.l
  3795.               ? vtmp->current_val.l[(*cl)->varmem] : NULL, 1);
  3796.         if(rc == 0){
  3797.             if(vtmp == &ps->vars[V_STANDARD_PRINTER])
  3798.               ps->printer_category = 2;
  3799.             else if(vtmp == &ps->vars[V_PERSONAL_PRINT_COMMAND])
  3800.               ps->printer_category = 3;
  3801.  
  3802.             set_variable(V_PERSONAL_PRINT_CATEGORY, 
  3803.             comatose(ps->printer_category), 0);
  3804.  
  3805.             p = NULL;
  3806.             if(i){
  3807.             char *nick, *q;
  3808.  
  3809.             parse_printer(vtmp->current_val.l[(*cl)->varmem],
  3810.                 &nick, &q, NULL, NULL, NULL, NULL);
  3811.             p = cpystr(*nick ? nick : q);
  3812.             fs_give((void **)&nick);
  3813.             fs_give((void **)&q);
  3814.             }
  3815.  
  3816.             q_status_message3(SM_ORDER,0,3, "Default printer %s%s%s",
  3817.             p ? "set to \"" : "unset", p ? p : "", p ? "\"" : ""); 
  3818.  
  3819.             if(p)
  3820.               fs_give((void **)&p);
  3821.         }
  3822.         else
  3823.           q_status_message(SM_ORDER,3,5,
  3824.             "Trouble setting default printer");
  3825.  
  3826.         retval = 1;
  3827.         }
  3828.         else if(!strcmp((*cl)->value,ANSI_PRINTER)){
  3829.         rc = set_variable(V_PRINTER, ANSI_PRINTER, 1);
  3830.         if(rc == 0){
  3831.             ps->printer_category = 1;
  3832.             set_variable(V_PERSONAL_PRINT_CATEGORY, 
  3833.             comatose(ps->printer_category), 0);
  3834.             q_status_message1(SM_ORDER,0,3,
  3835.             "Default printer set to \"%s\"", ANSI_PRINTER);
  3836.         }
  3837.         else
  3838.           q_status_message(SM_ORDER,3,5,
  3839.             "Trouble setting default printer");
  3840.  
  3841.         retval = 1;
  3842.         }
  3843.         else{
  3844.         char aname[100];
  3845.  
  3846.         strcat(strcpy(aname, ANSI_PRINTER), no_ff);
  3847.         if(!strcmp((*cl)->value,aname)){
  3848.             rc = set_variable(V_PRINTER, aname, 1);
  3849.             if(rc == 0){
  3850.             ps->printer_category = 1;
  3851.             set_variable(V_PERSONAL_PRINT_CATEGORY, 
  3852.                 comatose(ps->printer_category), 0);
  3853.             q_status_message1(SM_ORDER,0,3,
  3854.                 "Default printer set to \"%s\"", aname);
  3855.             }
  3856.             else
  3857.               q_status_message(SM_ORDER,3,5,
  3858.                 "Trouble setting default printer");
  3859.  
  3860.             retval = 1;
  3861.         }
  3862.         else
  3863.           retval = 0;
  3864.         }
  3865.     }
  3866.     else
  3867.       retval = 0;
  3868.  
  3869.     if(retval){
  3870.         ps->mangled_body = 1;    /* BUG: redraw it all for now? */
  3871.         set_def_printer_value(ps->VAR_PRINTER);
  3872.     }
  3873.  
  3874.     break;
  3875.  
  3876.       default:
  3877.     retval = -1;
  3878.     break;
  3879.     }
  3880.  
  3881.     return(retval);
  3882. }
  3883.  
  3884.  
  3885. int
  3886. print_edit_tool(ps, cmd, cl, flags)
  3887.     struct pine *ps;
  3888.     int          cmd;
  3889.     CONF_S     **cl;
  3890.     unsigned     flags;
  3891. {
  3892.     char         prompt[81], sval[MAXPATH+1], name[MAXPATH+1];
  3893.     char            *nick, *p, *tmp, **newval = NULL;
  3894.     int             rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
  3895.     int             changing_selected = 0;
  3896.     CONF_S        *ctmp;
  3897.     HelpType         help;
  3898.     ESCKEY_S         ekey[6];
  3899.  
  3900.     if(cmd == 's' || cmd == PF4 || cmd == ctrl('M') || cmd == ctrl('J'))
  3901.       return(print_select_tool(ps, cmd, cl, flags));
  3902.  
  3903.     if(!(cl && *cl && (*cl)->var))
  3904.       return(0);
  3905.  
  3906.     switch(cmd){
  3907.       case 'a':                    /* add to list */
  3908.       case PF9:
  3909.     sval[0] = '\0';
  3910.     if((*cl)->var->is_fixed)
  3911.       q_status_message(SM_ORDER, 3, 3,
  3912.                  "Can't add to sys-admin defined value.");
  3913.     else{
  3914.         int maxwidth = min(80,ps->ttyo->screen_cols) - 15;
  3915.  
  3916.         if((*cl)->var->user_val.l && (*cl)->value){
  3917.         strcpy(prompt, "Enter printer name : ");
  3918.         }
  3919.         else if(!(*cl)->var->user_val.l && (*cl)->var->current_val.l){
  3920.         /* Add to list which doesn't exist, but default does exist */
  3921.         ekey[0].ch    = 'r';
  3922.         ekey[0].rval  = 'r';
  3923.         ekey[0].name  = "R";
  3924.         ekey[0].label = "Replace";
  3925.         ekey[1].ch    = 'a';
  3926.         ekey[1].rval  = 'a';
  3927.         ekey[1].name  = "A";
  3928.         ekey[1].label = "Add To";
  3929.         ekey[2].ch    = -1;
  3930.         strcpy(prompt, "Replace or Add To default value ? ");
  3931.         switch(i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a',
  3932.                      'x', h_config_replace_add, RB_NORM)){
  3933.           case 'a':
  3934.             p = sval;
  3935.             for(j = 0; (*cl)->var->current_val.l[j]; j++){
  3936.             strcpy(p, (*cl)->var->current_val.l[j]);
  3937.             p += strlen(p);
  3938.             *p++ = ',';
  3939.             *p++ = ' ';
  3940.             *p = '\0';
  3941.             }
  3942.  
  3943. add_text:
  3944.             strcpy(prompt, "Enter name of printer to be added : ");
  3945.             break;
  3946.             
  3947.           case 'r':
  3948. replace_text:
  3949.             strcpy(prompt,
  3950.             "Enter the name for replacement printer : ");
  3951.             break;
  3952.             
  3953.           case 'x':
  3954.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  3955.             break;
  3956.         }
  3957.  
  3958.         if(i == 'x')
  3959.           break;
  3960.         }
  3961.         else
  3962.           strcpy(prompt, "Enter name of printer to be added : ");
  3963.  
  3964.         ps->mangled_footer = 1;
  3965.         help = NO_HELP;
  3966.  
  3967.         name[0] = '\0';
  3968.         i = 2;
  3969.         while(i != 0 && i != 1){
  3970.         if((*cl)->var->user_val.l && (*cl)->value){
  3971.             ekey[0].ch    = ctrl('W');
  3972.             ekey[0].rval  = 5;
  3973.             ekey[0].name  = "^W";
  3974.             ekey[0].label = after ? "InsertBefore" : "InsertAfter";
  3975.             ekey[1].ch    = -1;
  3976.         }
  3977.         else
  3978.           ekey[0].ch    = -1;
  3979.  
  3980.         i = optionally_enter(name, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  3981.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  3982.         if(i == 0){
  3983.             rv = ps->mangled_body = 1;
  3984.             removing_leading_white_space(name);
  3985.             removing_trailing_white_space(name);
  3986.         }
  3987.         else if(i == 1){
  3988.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  3989.         }
  3990.         else if(i == 3){
  3991.             help = (help == NO_HELP) ? h_config_insert_after : NO_HELP;
  3992.         }
  3993.         else if(i == 4){        /* no redraw, yet */
  3994.         }
  3995.         else if(i == 5){ /* change from/to prepend to/from append */
  3996.             after = after ? 0 : 1;
  3997.         }
  3998.         }
  3999.  
  4000.         if(i == 0)
  4001.           i = 2;
  4002.  
  4003. #ifdef OS2
  4004.         strcpy(prompt, "Enter port or |command : ");
  4005. #else
  4006.         strcpy(prompt, "Enter command for printer : ");
  4007. #endif
  4008.         while(i != 0 && i != 1){
  4009.         i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  4010.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  4011.         if(i == 0){
  4012.             rv = ps->mangled_body = 1;
  4013.             removing_leading_white_space(sval);
  4014.             removing_trailing_white_space(sval);
  4015.             if(*sval || !(*cl)->var->user_val.l){
  4016.             char **ltmp;
  4017.  
  4018.             for(tmp = sval; *tmp; tmp++)
  4019.               if(*tmp == ',')
  4020.                 i++;    /* conservative count of ,'s */
  4021.  
  4022.             if(!i){    /* only one item */
  4023.                 ltmp    = (char **)fs_get(2 * sizeof(char *));
  4024.                 ltmp[1] = NULL;
  4025.                 if(*name){
  4026.                 ltmp[0] = (char *)fs_get(strlen(name) + 1
  4027.                         + 2 + 1 + strlen(sval) + 1);
  4028.                 sprintf(ltmp[0], "%s [] %s", name, sval);
  4029.                 }
  4030.                 else
  4031.                   ltmp[0] = cpystr(sval);
  4032.             }
  4033.             else{
  4034.                 /*
  4035.                  * Don't allow input of multiple entries at once.
  4036.                  */
  4037.                 q_status_message(SM_ORDER,3,5,
  4038.                 "No commas allowed in command");
  4039.                 i = 2;
  4040.                 continue;
  4041.             }
  4042.  
  4043.             config_add_list(ps, cl, ltmp, &newval, after);
  4044.             if(after)
  4045.               skip_to_next = 1;
  4046.  
  4047.             fs_give((void **)<mp);
  4048.             }
  4049.             else
  4050.               q_status_message1(SM_ORDER, 0, 3,
  4051.                      "Can't add %s to list", empty_val);
  4052.         }
  4053.         else if(i == 1){
  4054.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  4055.         }
  4056.         else if(i == 3){
  4057.             help = help == NO_HELP ? h_config_print_cmd : NO_HELP;
  4058.         }
  4059.         else if(i == 4){        /* no redraw, yet */
  4060.         }
  4061.         else if(i == 5){ /* change from/to prepend to/from append */
  4062.             after = after ? 0 : 1;
  4063.         }
  4064.         }
  4065.     }
  4066.  
  4067.     break;
  4068.  
  4069.       case 'd':                    /* delete */
  4070.       case PF10:
  4071.     if((*cl)->var->current_val.l
  4072.       && (*cl)->var->current_val.l[(*cl)->varmem]
  4073.       && !strucmp(ps->VAR_PRINTER,(*cl)->var->current_val.l[(*cl)->varmem]))
  4074.         changing_selected = 1;
  4075.  
  4076.     if(!(*cl)->var->user_val.l && (*cl)->var->current_val.l){
  4077.         char pmt[40];
  4078.  
  4079.         sprintf(pmt, "Override default with %s", empty_val2);
  4080.         if(want_to(pmt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  4081.         char **ltmp;
  4082.  
  4083.         sval[0] = '\0';
  4084.         ltmp    = (char **)fs_get(2 * sizeof(char *));
  4085.         ltmp[0] = cpystr(sval);
  4086.         ltmp[1] = NULL;
  4087.         config_add_list(ps, cl, ltmp, &newval, 0);
  4088.         fs_give((void **)<mp);
  4089.         rv = ps->mangled_body = 1;
  4090.         }
  4091.     }
  4092.     else if(!(*cl)->var->user_val.l){
  4093.         q_status_message(SM_ORDER, 0, 3, "No set value to delete");
  4094.     }
  4095.     else{
  4096.         if((*cl)->var->is_fixed){
  4097.         parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4098.             &nick, &p, NULL, NULL, NULL, NULL);
  4099.             sprintf(prompt, "Delete (unused) printer %.30s ",
  4100.             *nick ? nick : (!*p) ? empty_val2 : p);
  4101.         fs_give((void **)&nick);
  4102.         fs_give((void **)&p);
  4103.         }
  4104.         else
  4105.           sprintf(prompt, "Really delete item %.20s from printer list ",
  4106.             int2string((*cl)->varmem + 1));
  4107.  
  4108.         ps->mangled_footer = 1;
  4109.         if(want_to(prompt, 'n', 'n', h_config_print_del, 0, 1) == 'y'){
  4110.         rv = ps->mangled_body = 1;
  4111.         fs_give((void **)&(*cl)->var->user_val.l[(*cl)->varmem]);
  4112.         config_del_list_item(cl, &newval);
  4113.         }
  4114.         else
  4115.           q_status_message(SM_ORDER, 0, 3, "Printer not deleted");
  4116.     }
  4117.  
  4118.     break;
  4119.  
  4120.       case 'c':                    /* edit/change list option */
  4121.       case PF11:
  4122.     if((*cl)->var->current_val.l
  4123.       && (*cl)->var->current_val.l[(*cl)->varmem]
  4124.       && !strucmp(ps->VAR_PRINTER,(*cl)->var->current_val.l[(*cl)->varmem]))
  4125.         changing_selected = 1;
  4126.  
  4127.     if((*cl)->var->is_fixed)
  4128.       q_status_message(SM_ORDER, 3, 3,
  4129.                  "Can't change sys-admin defined printer.");
  4130.     else if(!(*cl)->var->user_val.l && (*cl)->var->current_val.l)
  4131.       goto replace_text;
  4132.     else if(!(*cl)->var->user_val.l && !(*cl)->var->current_val.l)
  4133.       goto add_text;
  4134.     else{
  4135.         HelpType help;
  4136.  
  4137.         ekey[0].ch    = 'n';
  4138.         ekey[0].rval  = 'n';
  4139.         ekey[0].name  = "N";
  4140.         ekey[0].label = "Name";
  4141.         ekey[1].ch    = 'c';
  4142.         ekey[1].rval  = 'c';
  4143.         ekey[1].name  = "C";
  4144.         ekey[1].label = "Command";
  4145.         ekey[2].ch    = 'o';
  4146.         ekey[2].rval  = 'o';
  4147.         ekey[2].name  = "O";
  4148.         ekey[2].label = "Options";
  4149.         ekey[3].ch    = -1;
  4150.         strcpy(prompt, "Change Name or Command or Options ? ");
  4151.         i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'c', 'x',
  4152.                   h_config_print_name_cmd, RB_NORM);
  4153.  
  4154.         if(i == 'x'){
  4155.         q_status_message(SM_ORDER,0,3,"Change cancelled");
  4156.         break;
  4157.         } 
  4158.         else if(i == 'c'){
  4159.         char *all_but_cmd;
  4160.  
  4161.         parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4162.             NULL, &p, NULL, NULL, NULL, &all_but_cmd);
  4163.         
  4164.         strcpy(prompt, "Change command : ");
  4165.         strcpy(sval, p ? p : "");
  4166.         fs_give((void **)&p);
  4167.  
  4168.         ps->mangled_footer = 1;
  4169.         help = NO_HELP;
  4170.         while(1){
  4171.             i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  4172.                  0, prompt, NULL, help, 0);
  4173.             if(i == 0){
  4174.             removing_leading_white_space(sval);
  4175.             removing_trailing_white_space(sval);
  4176.             rv = ps->mangled_body = 1;
  4177.             if((*cl)->var->user_val.l[(*cl)->varmem])
  4178.               fs_give((void **)&(*cl)->var->user_val.l[
  4179.                                    (*cl)->varmem]);
  4180.  
  4181.             i = 0;
  4182.             for(tmp = sval; *tmp; tmp++)
  4183.               if(*tmp == ',')
  4184.                 i++;    /* count of ,'s */
  4185.  
  4186.             if(!i){    /* only one item */
  4187.                 (*cl)->var->user_val.l[(*cl)->varmem]
  4188.                   = (char *)fs_get(strlen(all_but_cmd) +
  4189.                         strlen(sval) + 1);
  4190.                 strcpy((*cl)->var->user_val.l[(*cl)->varmem],
  4191.                     all_but_cmd);
  4192.                 strcat((*cl)->var->user_val.l[(*cl)->varmem],
  4193.                     sval);
  4194.  
  4195.                 newval = &(*cl)->value;
  4196.             }
  4197.             else{
  4198.                 /*
  4199.                  * Don't allow input of multiple entries at once.
  4200.                  */
  4201.                 q_status_message(SM_ORDER,3,5,
  4202.                 "No commas allowed in command");
  4203.                 continue;
  4204.             }
  4205.             }
  4206.             else if(i == 1){
  4207.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  4208.             }
  4209.             else if(i == 3){
  4210.             help = help == NO_HELP ? h_config_change : NO_HELP;
  4211.             continue;
  4212.             }
  4213.             else if(i == 4){        /* no redraw, yet */
  4214.             continue;
  4215.             }
  4216.  
  4217.             break;
  4218.         }
  4219.         }
  4220.         else if(i == 'n'){
  4221.         char *all_but_nick;
  4222.  
  4223.         parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4224.             &p, NULL, NULL, NULL, &all_but_nick, NULL);
  4225.         
  4226.         strcpy(prompt, "Change name : ");
  4227.         strcpy(name, p ? p : "");
  4228.         fs_give((void **)&p);
  4229.  
  4230.         ps->mangled_footer = 1;
  4231.         help = NO_HELP;
  4232.         while(1){
  4233.             i = optionally_enter(name, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  4234.                  0, prompt, NULL, help, 0);
  4235.             if(i == 0){
  4236.             rv = ps->mangled_body = 1;
  4237.             removing_leading_white_space(name);
  4238.             removing_trailing_white_space(name);
  4239.             if((*cl)->var->user_val.l[(*cl)->varmem])
  4240.               fs_give((void **)&(*cl)->var->user_val.l[
  4241.                                    (*cl)->varmem]);
  4242.  
  4243.             (*cl)->var->user_val.l[(*cl)->varmem]
  4244.               = (char *)fs_get(strlen(name) + 1
  4245.                     + ((*all_but_nick == '[') ? 0 : 3)
  4246.                     + strlen(all_but_nick) + 1);
  4247.             sprintf((*cl)->var->user_val.l[(*cl)->varmem],
  4248.                 "%s %s%s", name,
  4249.                 (*all_but_nick == '[') ? "" : "[] ",
  4250.                 all_but_nick);
  4251.             
  4252.             newval = &(*cl)->value;
  4253.             }
  4254.             else if(i == 1){
  4255.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  4256.             }
  4257.             else if(i == 3){
  4258.             help = help == NO_HELP ? h_config_change : NO_HELP;
  4259.             continue;
  4260.             }
  4261.             else if(i == 4){        /* no redraw, yet */
  4262.             continue;
  4263.             }
  4264.  
  4265.             break;
  4266.         }
  4267.         
  4268.         fs_give((void **)&all_but_nick);
  4269.         }
  4270.         else if(i == 'o'){
  4271.         HelpType help;
  4272.  
  4273.         ekey[0].ch    = 'i';
  4274.         ekey[0].rval  = 'i';
  4275.         ekey[0].name  = "I";
  4276.         ekey[0].label = "Init";
  4277.         ekey[1].ch    = 't';
  4278.         ekey[1].rval  = 't';
  4279.         ekey[1].name  = "T";
  4280.         ekey[1].label = "Trailer";
  4281.         ekey[2].ch    = -1;
  4282.         strcpy(prompt, "Change Init string or Trailer string ? ");
  4283.         j = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'i', 'x',
  4284.                   h_config_print_opt_choice, RB_NORM);
  4285.  
  4286.         if(j == 'x'){
  4287.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  4288.             break;
  4289.         } 
  4290.         else{
  4291.             char *init, *trailer;
  4292.  
  4293.             parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4294.             &nick, &p, &init, &trailer, NULL, NULL);
  4295.             
  4296.             sprintf(prompt, "Change %s string : ",
  4297.             (j == 'i') ? "INIT" : "TRAILER");
  4298.             strcpy(sval, (j == 'i') ? init : trailer);
  4299.  
  4300.             tmp = string_to_cstring(sval);
  4301.             strcpy(sval, tmp);
  4302.             fs_give((void **)&tmp);
  4303.             
  4304.             ps->mangled_footer = 1;
  4305.             help = NO_HELP;
  4306.             while(1){
  4307.             i = optionally_enter(sval, -FOOTER_ROWS(ps), 0,
  4308.                 MAXPATH, 1, 0, prompt, NULL, help, 0);
  4309.             if(i == 0){
  4310.                 removing_leading_white_space(sval);
  4311.                 removing_trailing_white_space(sval);
  4312.                 rv = 1;
  4313.                 if((*cl)->var->user_val.l[(*cl)->varmem])
  4314.                   fs_give((void **)&(*cl)->var->user_val.l[
  4315.                                    (*cl)->varmem]);
  4316.                 if(j == 'i'){
  4317.                 init = cstring_to_hexstring(sval);
  4318.                 tmp = cstring_to_hexstring(trailer);
  4319.                 fs_give((void **)&trailer);
  4320.                 trailer = tmp;
  4321.                 }
  4322.                 else{
  4323.                 trailer = cstring_to_hexstring(sval);
  4324.                 tmp = cstring_to_hexstring(init);
  4325.                 fs_give((void **)&init);
  4326.                 init = tmp;
  4327.                 }
  4328.  
  4329.                 (*cl)->var->user_val.l[(*cl)->varmem]
  4330.                   = (char *)fs_get(strlen(nick) + 1
  4331.                   + 2 + strlen("INIT=") + strlen(init)
  4332.                   + 1 + strlen("TRAILER=") + strlen(trailer)
  4333.                   + 1 + strlen(p) + 1);
  4334.                 sprintf((*cl)->var->user_val.l[(*cl)->varmem],
  4335.                 "%s%s%s%s%s%s%s%s%s%s%s",
  4336.         /* nick */        nick,
  4337.         /* space */        *nick ? " " : "",
  4338.         /* [ */            (*nick || *init || *trailer) ? "[" : "",
  4339.         /* INIT= */        *init ? "INIT=" : "",
  4340.         /* init */        init,
  4341.         /* space */        (*init && *trailer) ? " " : "",
  4342.         /* TRAILER= */        *trailer ? "TRAILER=" : "",
  4343.         /* trailer */        trailer,
  4344.         /* ] */            (*nick || *init || *trailer) ? "]" : "",
  4345.         /* space */        (*nick || *init || *trailer) ? " " : "",
  4346.         /* command */        p);
  4347.         
  4348.                 newval = &(*cl)->value;
  4349.             }
  4350.             else if(i == 1){
  4351.                 q_status_message(SM_ORDER,0,3,"Change cancelled");
  4352.             }
  4353.             else if(i == 3){
  4354.                 help=(help == NO_HELP)?h_config_print_init:NO_HELP;
  4355.                 continue;
  4356.             }
  4357.             else if(i == 4){        /* no redraw, yet */
  4358.                 continue;
  4359.             }
  4360.  
  4361.             break;
  4362.             }
  4363.  
  4364.             fs_give((void **)&nick);
  4365.             fs_give((void **)&p);
  4366.             fs_give((void **)&init);
  4367.             fs_give((void **)&trailer);
  4368.         }
  4369.         }
  4370.     }
  4371.  
  4372.     break;
  4373.  
  4374.       case 'e':                    /* exit */
  4375.       case PF3:
  4376.     rv = config_exit_cmd(flags);
  4377.     break;
  4378.  
  4379.       default:
  4380.     rv = -1;
  4381.     break;
  4382.     }
  4383.  
  4384.     if(skip_to_next)
  4385.       *cl = next_confline(*cl);
  4386.  
  4387.     /*
  4388.      * At this point, if changes occurred, var->user_val.X is set.
  4389.      * So, fix the current_val, and handle special cases...
  4390.      */
  4391.     if(rv == 1){
  4392.     set_current_val((*cl)->var, TRUE, FALSE);
  4393.     fix_side_effects(ps, (*cl)->var, 0);
  4394.  
  4395.     if(newval){
  4396.         if(*newval)
  4397.           fs_give((void **)newval);
  4398.         
  4399.         if((*cl)->var->current_val.l)
  4400.           *newval = printer_name((*cl)->var->current_val.l[(*cl)->varmem]);
  4401.         else
  4402.           *newval = cpystr("");
  4403.     }
  4404.  
  4405.     if(changing_selected)
  4406.       print_select_tool(ps, 's', cl, flags);
  4407.     }
  4408.  
  4409.     return(rv);
  4410. }
  4411.  
  4412.  
  4413.  
  4414. /*
  4415.  * Manage display of the config/options menu body.
  4416.  */
  4417. void
  4418. update_option_screen(ps, screen, cursor_pos)
  4419.     struct pine  *ps;
  4420.     OPT_SCREEN_S *screen;
  4421.     Pos          *cursor_pos;
  4422. {
  4423.     int           dline;
  4424.     CONF_S      *top_line, *ctmp;
  4425.  
  4426. #ifdef _WINDOWS
  4427.     mswin_beginupdate();
  4428. #endif
  4429.     if(cursor_pos){
  4430.     cursor_pos->col = 0;
  4431.     cursor_pos->row = -1;        /* to tell us if we've set it yet */
  4432.     }
  4433.  
  4434.     /*
  4435.      * calculate top line of display for reframing if the current field
  4436.      * is off the display defined by screen->top_line...
  4437.      */
  4438.     if(ctmp = screen->top_line)
  4439.       for(dline = BODY_LINES(ps);
  4440.       dline && ctmp && ctmp != screen->current;
  4441.       ctmp = next_confline(ctmp), dline--)
  4442.     ;
  4443.  
  4444.     if(!ctmp || !dline){        /* force reframing */
  4445.     dline = 0;
  4446.     ctmp = top_line = first_confline(screen->current);
  4447.     do
  4448.       if(((dline++)%BODY_LINES(ps)) == 0)
  4449.         top_line = ctmp;
  4450.     while(ctmp != screen->current && (ctmp = next_confline(ctmp)));
  4451.     }
  4452.     else
  4453.       top_line = screen->top_line;
  4454.  
  4455. #ifdef _WINDOWS
  4456.     /*
  4457.      * Figure out how far down the top line is from the top and how many
  4458.      * total lines there are.  Dumb to loop every time thru, but
  4459.      * there aren't that many lines, and it's cheaper than rewriting things
  4460.      * to maintain a line count in each structure...
  4461.      */
  4462.     for(dline = 0, ctmp = top_line; ctmp; ctmp = prev_confline(ctmp))
  4463.       dline++;
  4464.  
  4465.     scroll_setpos(dline - 1L);
  4466.  
  4467.     for(ctmp = next_confline(top_line); ctmp ; ctmp = next_confline(ctmp))
  4468.       dline++;
  4469.  
  4470.     scroll_setrange(dline);
  4471. #endif
  4472.  
  4473.     /* mangled body or new page, force redraw */
  4474.     if(ps->mangled_body || screen->top_line != top_line)
  4475.       screen->prev = NULL;
  4476.  
  4477.     /* loop thru painting what's needed */
  4478.     for(dline = 0, ctmp = top_line;
  4479.     dline < BODY_LINES(ps);
  4480.     dline++, ctmp = next_confline(ctmp)){
  4481.  
  4482.     /*
  4483.      * only fall thru painting if something needs painting...
  4484.      */
  4485.     if(!(!screen->prev || ctmp == screen->prev || ctmp == screen->current
  4486.          || ctmp == screen->prev->varnamep
  4487.          || ctmp == screen->current->varnamep
  4488.          || ctmp == screen->prev->headingp
  4489.          || ctmp == screen->current->headingp))
  4490.       continue;
  4491.  
  4492.     ClearLine(dline + HEADER_ROWS(ps));
  4493.  
  4494.     if(ctmp && ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
  4495.         if(ctmp == screen->current && cursor_pos)
  4496.           cursor_pos->row  = dline + HEADER_ROWS(ps);
  4497.  
  4498.         if((ctmp == screen->current || ctmp == screen->current->varnamep
  4499.                || ctmp == screen->current->headingp)
  4500.            && !(ctmp->flags & CF_NOHILITE))
  4501.           StartInverse();
  4502.  
  4503.         if(ctmp->varoffset)
  4504.           MoveCursor(dline+HEADER_ROWS(ps), ctmp->varoffset);
  4505.  
  4506.         Write_to_screen(ctmp->varname);
  4507.         if((ctmp == screen->current || ctmp == screen->current->varnamep
  4508.                || ctmp == screen->current->headingp)
  4509.            && !(ctmp->flags & CF_NOHILITE))
  4510.           EndInverse();
  4511.     }
  4512.  
  4513.     if(ctmp && ctmp->value){
  4514.         char *p = tmp_20k_buf;
  4515.         int   i, j;
  4516.         if(ctmp == screen->current){
  4517.         StartInverse();
  4518.         if(cursor_pos)
  4519.           cursor_pos->row  = dline + HEADER_ROWS(ps);
  4520.         }
  4521.  
  4522.         /*
  4523.          * Copy the value to a temp buffer expanding tabs, and
  4524.          * making sure not to write beyond screen right...
  4525.          */
  4526.         for(i = 0, j = ctmp->valoffset;
  4527.         ctmp->value[i] && j < ps->ttyo->screen_cols;
  4528.         i++){
  4529.         if(ctmp->value[i] == ctrl('I')){
  4530.             do
  4531.               *p++ = ' ';
  4532.             while(j < ps_global->ttyo->screen_cols && ((++j)&0x07));
  4533.               
  4534.         }
  4535.         else{
  4536.             *p++ = ctmp->value[i];
  4537.             j++;
  4538.         }
  4539.         }
  4540.  
  4541.         *p = '\0';
  4542.         if(ctmp == screen->current && cursor_pos){
  4543.         cursor_pos->col = ctmp->valoffset;
  4544.         if(ctmp->tool==radiobutton_tool || ctmp->tool==checkbox_tool)
  4545.           cursor_pos->col++;
  4546.         }
  4547.  
  4548.         PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, tmp_20k_buf);
  4549.         if(ctmp == screen->current)
  4550.           EndInverse();
  4551.     }
  4552.     }
  4553.  
  4554.     ps->mangled_body = 0;
  4555.     screen->top_line = top_line;
  4556.     screen->prev     = screen->current;
  4557. #ifdef _WINDOWS
  4558.     mswin_endupdate();
  4559. #endif
  4560. }
  4561.  
  4562.  
  4563.  
  4564. /*
  4565.  * 
  4566.  */
  4567. void
  4568. print_option_screen(screen, prompt)
  4569.     OPT_SCREEN_S *screen;
  4570.     char *prompt;
  4571. {
  4572.     CONF_S *ctmp;
  4573.     int     so_far;
  4574.     char    line[500];
  4575.  
  4576.     if(open_printer(prompt) == 0){
  4577.     for(ctmp = first_confline(screen->current);
  4578.         ctmp;
  4579.         ctmp = next_confline(ctmp)){
  4580.  
  4581.         so_far = 0;
  4582.         if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
  4583.  
  4584.         sprintf(line, "%*s%s", ctmp->varoffset, "", ctmp->varname);
  4585.         print_text(line);
  4586.         so_far = ctmp->varoffset + strlen(ctmp->varname);
  4587.         }
  4588.  
  4589.         if(ctmp && ctmp->value){
  4590.         char *p = tmp_20k_buf;
  4591.         int   i, j, spaces;
  4592.  
  4593.         /* Copy the value to a temp buffer expanding tabs. */
  4594.         for(i = 0, j = ctmp->valoffset; ctmp->value[i]; i++){
  4595.             if(ctmp->value[i] == ctrl('I')){
  4596.             do
  4597.               *p++ = ' ';
  4598.             while((++j) & 0x07);
  4599.                   
  4600.             }
  4601.             else{
  4602.             *p++ = ctmp->value[i];
  4603.             j++;
  4604.             }
  4605.         }
  4606.  
  4607.         *p = '\0';
  4608.         removing_trailing_white_space(tmp_20k_buf);
  4609.  
  4610.         spaces = max(ctmp->valoffset - so_far, 0);
  4611.         sprintf(line, "%*s%s\n", spaces, "", tmp_20k_buf);
  4612.         print_text(line);
  4613.         }
  4614.     }
  4615.  
  4616.     close_printer();
  4617.     }
  4618. }
  4619.  
  4620.  
  4621.  
  4622. /*
  4623.  *
  4624.  */
  4625. void
  4626. option_screen_redrawer()
  4627. {
  4628.     ps_global->mangled_body = 1;
  4629.     update_option_screen(ps_global, opt_screen, (Pos *)NULL);
  4630. }
  4631.  
  4632.  
  4633.  
  4634. /*
  4635.  * pretty_value - given the variable and, if list, member, return an
  4636.  *                alloc'd string containing var's value...
  4637.  */
  4638. char *
  4639. pretty_value(ps, cl)
  4640.     struct pine *ps;
  4641.     CONF_S      *cl;
  4642. {
  4643.     char tmp[MAXPATH];
  4644.  
  4645.     if(cl->var->is_list){
  4646.     if(!cl->var->is_fixed && cl->var->user_val.l){
  4647.         sprintf(tmp, "%-*s", ps->ttyo->screen_cols - cl->valoffset,
  4648.             (*cl->var->user_val.l[cl->varmem])
  4649.                ? cl->var->user_val.l[cl->varmem]
  4650.                : empty_val2);
  4651.     }
  4652.     else{
  4653.         char *p = tmp;
  4654.         *p++ = '<';
  4655.         *p   = '\0';
  4656.         sstrcpy(&p, cl->var->is_fixed ? fixed_val : no_val);
  4657.         if(cl->var->current_val.l){
  4658.         int i, l, l2;
  4659.  
  4660.         sstrcpy(&p, ": using \"");
  4661.         for(i = 0; cl->var->current_val.l[i]; i++){
  4662.             if(i)
  4663.               *p++ = ',';
  4664.  
  4665.             if((l=ps->ttyo->screen_cols-cl->valoffset-(p-tmp)-2) > 0){
  4666.             strncpy(p, cl->var->current_val.l[i], l);
  4667.             if(l < (l2 = strlen(cl->var->current_val.l[i]))){
  4668.                 strncpy(p += (l - 4), " ...", 4);
  4669.                 p += 4;
  4670.                 break;
  4671.             }
  4672.             else
  4673.               p += l2;
  4674.             }
  4675.             else
  4676.               break;
  4677.         }
  4678.  
  4679.         *p++ = '\"';
  4680.         }
  4681.  
  4682.         sprintf(p, ">%*s", max(0, ps->ttyo->screen_cols - cl->valoffset
  4683.                                  - (p - tmp)),
  4684.             "");
  4685.     }
  4686.  
  4687.     }
  4688.     else if(cl->var->is_fixed || !cl->var->user_val.p){
  4689.     sprintf(tmp, cl->var->is_fixed
  4690.             ? "<%s%s%s%s>%*s" : "<%s%s%s%s>%*s", 
  4691.         cl->var->is_fixed ? fixed_val : no_val,
  4692.         (cl->var->current_val.p) ? ": using \"" : "",
  4693.         (cl->var->current_val.p) ? cl->var->current_val.p : "",
  4694.         (cl->var->current_val.p) ? "\"" : "",
  4695.         max(0, ps->ttyo->screen_cols - cl->valoffset - 13
  4696.                   - ((cl->var->current_val.p) ? 9 : 0)
  4697.                   - ((cl->var->current_val.p)
  4698.                        ? strlen(cl->var->current_val.p) : 0)
  4699.                   - ((cl->var->current_val.p) ? 1 : 0)),
  4700.         "");
  4701.     }
  4702.     else
  4703.       sprintf(tmp, "%-*s", ps->ttyo->screen_cols - cl->valoffset,
  4704.           (*cl->var->user_val.p) ? cl->var->user_val.p
  4705.                     : empty_val2);
  4706.  
  4707.     return(cpystr(tmp));
  4708. }
  4709.  
  4710.  
  4711. /*
  4712.  * test_feature - runs thru a feature list, and returns:
  4713.  *                 1 if feature explicitly set and matches 'v'
  4714.  *                 0 if feature not explicitly set *or* doesn't match 'v'
  4715.  */
  4716. int
  4717. test_feature(l, f, g, v)
  4718.     char **l;
  4719.     char  *f;
  4720.     int    g, v;
  4721. {
  4722.     char *p;
  4723.     int   rv = 0, forced_off;
  4724.  
  4725.     for(; l && *l; l++){
  4726.     p = (forced_off = !struncmp(*l, "no-", 3)) ? *l + 3 : *l;
  4727.     if(!strucmp(p, f))
  4728.       rv = (v == !forced_off);
  4729.     else if(g && !strucmp(p, "old-growth"))
  4730.       rv = (v == forced_off);
  4731.     }
  4732.  
  4733.     return(rv);
  4734. }
  4735.  
  4736.  
  4737. void
  4738. clear_feature(l, f)
  4739.     char ***l;
  4740.     char   *f;
  4741. {
  4742.     char **list = l ? *l : NULL, newval[256];
  4743.     int    count = 0;
  4744.  
  4745.     for(; list && *list; list++, count++){
  4746.     if(f && !strucmp(((!struncmp(*list,"no-",3)) ? *list + 3 : *list), f)){
  4747.         fs_give((void **)list);
  4748.         f = NULL;
  4749.     }
  4750.  
  4751.     if(!f)                    /* shift  */
  4752.       *list = *(list + 1);
  4753.     }
  4754.  
  4755.     /*
  4756.      * this is helpful to keep the array from growing if a feature
  4757.      * get's set and unset repeatedly
  4758.      */
  4759.     if(!f)
  4760.       fs_resize((void **)l, count * sizeof(char *));
  4761. }
  4762.  
  4763.  
  4764. void
  4765. set_feature(l, f, v)
  4766.     char ***l;
  4767.     char   *f;
  4768.     int     v;
  4769. {
  4770.     char **list = l ? *l : NULL, newval[256];
  4771.     int    count = 0;
  4772.  
  4773.     sprintf(newval, "%s%s", v ? "" : "no-", f);
  4774.     for(; list && *list; list++, count++)
  4775.       if(!strucmp(((!struncmp(*list, "no-", 3)) ? *list + 3 : *list), f)){
  4776.       fs_give((void **)list);        /* replace with new value */
  4777.       *list = cpystr(newval);
  4778.       return;
  4779.       }
  4780.  
  4781.     /*
  4782.      * if we got here, we didn't find it in the list, so grow the list
  4783.      * and add it..
  4784.      */
  4785.     if(!*l)
  4786.       *l = (char **)fs_get((count + 2) * sizeof(char *));
  4787.     else
  4788.       fs_resize((void **)l, (count + 2) * sizeof(char *));
  4789.  
  4790.     (*l)[count]     = cpystr(newval);
  4791.     (*l)[count + 1] = NULL;
  4792. }
  4793.  
  4794.  
  4795. /*
  4796.  *
  4797.  */
  4798. void
  4799. toggle_feature_bit(ps, index, var, value)
  4800.     struct pine     *ps;
  4801.     int             index;
  4802.     struct variable *var;
  4803.     char            *value;
  4804. {
  4805.     NAMEVAL_S  *f;
  4806.     char      **vp, *p;
  4807.     int        i, og;
  4808.  
  4809.     f  = feature_list(index);
  4810.     og = test_old_growth_bits(ps, f->value);
  4811.  
  4812.     /*
  4813.      * if this feature is in the fixed set, or old-growth is in the fixed
  4814.      * set and this feature is in the old-growth set, don't alter it...
  4815.      */
  4816.     for(vp = var->fixed_val.l; vp && *vp; vp++){
  4817.     p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
  4818.     if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
  4819.         q_status_message(SM_ORDER, 3, 3,
  4820.                  "Can't change value fixed by sys-admin.");
  4821.         return;
  4822.     }
  4823.     }
  4824.  
  4825.     F_SET(f->value, ps, !F_ON(f->value, ps));    /* flip the bit */
  4826.     if(value)
  4827.       value[1] = F_ON(f->value, ps) ? 'X' : ' ';
  4828.  
  4829.     /*
  4830.      * fix up the user's feature list based on global and current
  4831.      * settings..
  4832.      *
  4833.      * Note, we only care if "old-growth" is set or not in as much as
  4834.      * we don't want to add redundant feature entries.  we won't add or 
  4835.      * remove "old-growth" in that the set it defines may change in the
  4836.      * future...
  4837.      */
  4838.     if(test_feature(var->global_val.l,f->name,og,F_ON(f->value,ps))
  4839.        || test_feature(var->user_val.l,f->name,og,!F_ON(f->value,ps)))
  4840.       clear_feature(&var->user_val.l, f->name);
  4841.     else
  4842.       set_feature(&var->user_val.l, f->name, F_ON(f->value, ps));
  4843.  
  4844.     /*
  4845.      * Handle any features that need special attention here...
  4846.      */
  4847.     if(f->value == F_QUOTE_ALL_FROMS)
  4848.       mail_parameters(NULL,SET_FROMWIDGET,(void *)(F_ON(f->value,ps) ? 1 : 0));
  4849.     else if(f->value == F_QUELL_LOCK_FAILURE_MSGS)
  4850.       mail_parameters(NULL, SET_LOCKEACCESERROR,
  4851.               (void *)(F_ON(f->value,ps) ? 1 : 0));
  4852.     else if(f->value == F_ENABLE_INCOMING &&  F_ON(f->value, ps)){
  4853.     q_status_message(SM_ORDER | SM_DING, 3, 4,
  4854.         "Folder List changes will take effect your next pine session.");
  4855.     }
  4856.     else if(f->value == F_PRESERVE_START_STOP){
  4857.     /* toggle raw mode settings to make tty driver aware of new setting */
  4858.     Raw(0);
  4859.     Raw(1);
  4860.     }
  4861.     else if(f->value == F_BLANK_KEYMENU){
  4862.     clearfooter(ps);
  4863.     if(F_ON(f->value,ps)){
  4864.         FOOTER_ROWS(ps) = 1;
  4865.         ps->mangled_body = 1;
  4866.     }
  4867.     else{
  4868.         FOOTER_ROWS(ps) = 3;
  4869.         ps->mangled_footer = 1;
  4870.     }
  4871.     }
  4872. #if !defined(DOS) && !defined(OS2)
  4873.     else if(f->value == F_ALLOW_TALK){
  4874.     if(F_ON(f->value,ps))
  4875.       allow_talk(ps);
  4876.     else
  4877.       disallow_talk(ps);
  4878.     }
  4879. #endif
  4880. #ifdef    MOUSE
  4881.     else if(f->value == F_ENABLE_MOUSE){
  4882.     if(F_ON(f->value,ps))
  4883.       init_mouse();
  4884.     else
  4885.       end_mouse();
  4886.     }
  4887. #endif
  4888. }
  4889.  
  4890.  
  4891. /*
  4892.  * new_confline - create new CONF_S zero it out, and insert it after current.
  4893.  *                NOTE current gets set to the new CONF_S too!
  4894.  */
  4895. CONF_S *
  4896. new_confline(current)
  4897.     CONF_S **current;
  4898. {
  4899.     CONF_S *p;
  4900.  
  4901.     p = (CONF_S *)fs_get(sizeof(CONF_S));
  4902.     memset((void *)p, 0, sizeof(CONF_S));
  4903.     if(current){
  4904.     if(*current){
  4905.         p->next         = (*current)->next;
  4906.         (*current)->next = p;
  4907.         p->prev         = *current;
  4908.         if(p->next)
  4909.           p->next->prev = p;
  4910.     }
  4911.  
  4912.     *current = p;
  4913.     }
  4914.  
  4915.     return(p);
  4916. }
  4917.  
  4918.  
  4919. /*
  4920.  *
  4921.  */
  4922. void
  4923. free_confline(p)
  4924.     CONF_S **p;
  4925. {
  4926.     if(p){
  4927.     if((*p)->varname)
  4928.       fs_give((void **)&(*p)->varname);
  4929.  
  4930.     if((*p)->value)
  4931.       fs_give((void **)&(*p)->value);
  4932.  
  4933.     if((*p)->prev)
  4934.       (*p)->prev->next = (*p)->next;
  4935.  
  4936.     if((*p)->next)
  4937.       (*p)->next->prev = (*p)->prev;
  4938.  
  4939.     fs_give((void **)p);
  4940.     }
  4941. }
  4942.  
  4943.  
  4944. /*
  4945.  *
  4946.  */
  4947. CONF_S *
  4948. first_confline(p)
  4949.     CONF_S *p;
  4950. {
  4951.     while(p && p->prev)
  4952.       p = p->prev;
  4953.  
  4954.     return(p);
  4955. }
  4956.  
  4957.  
  4958. /*
  4959.  * First selectable confline.
  4960.  */
  4961. CONF_S *
  4962. first_sel_confline(p)
  4963.     CONF_S *p;
  4964. {
  4965.     for(p = first_confline(p); p && (p->flags&CF_NOSELECT); p=next_confline(p))
  4966.       ;/* do nothing */
  4967.  
  4968.     return(p);
  4969. }
  4970.  
  4971.  
  4972. /*
  4973.  *
  4974.  */
  4975. CONF_S *
  4976. last_confline(p)
  4977.     CONF_S *p;
  4978. {
  4979.     while(p && p->next)
  4980.       p = p->next;
  4981.  
  4982.     return(p);
  4983. }
  4984.  
  4985.  
  4986. int
  4987. offer_to_fix_pinerc(ps)
  4988.     struct pine *ps;
  4989. {
  4990.     struct variable *v;
  4991.     char             prompt[300];
  4992.     char            *p, *q;
  4993.     char           **list;
  4994.     char           **list_fixed;
  4995.     int              rv = 0;
  4996.     int              i, k, need;
  4997.     char            *clear = ": delete it";
  4998.  
  4999.     ps->fix_fixed_warning = 0;  /* so we only ask first time */
  5000.  
  5001.     if(ps->readonly_pinerc)
  5002.       return(rv);
  5003.  
  5004.     if(want_to("Some of your options conflict with site policy.  Investigate",
  5005.     'y', 'n', NO_HELP, 0, 1) != 'y')
  5006.       return(rv);
  5007.     
  5008. /* space want_to requires in addition to the string you pass in */
  5009. #define WANTTO_SPACE 6
  5010.     need = WANTTO_SPACE + strlen(clear);
  5011.  
  5012.     for(v = ps->vars; v->name; v++){
  5013.     if(!v->is_fixed ||
  5014.        !v->is_user ||
  5015.         v->is_obsolete ||
  5016.         v == &ps->vars[V_FEATURE_LIST]) /* handle feature-list below */
  5017.       continue;
  5018.     
  5019.     prompt[0] = '\0';
  5020.     
  5021.     if(v->is_list && v->user_val.l){
  5022.         if(*v->user_val.l){
  5023.         sprintf(prompt, "Your setting for %s is ", v->name);
  5024.         p = prompt + strlen(prompt);
  5025.         for(i = 0; v->user_val.l[i]; i++){
  5026.             if(p - prompt > ps->ttyo->screen_cols - need)
  5027.               break;
  5028.             if(i)
  5029.               *p++ = ',';
  5030.             sstrcpy(&p, v->user_val.l[i]);
  5031.         }
  5032.         *p = '\0';
  5033.         }
  5034.         else
  5035.           sprintf(prompt, "Your setting for %s is %s", v->name, empty_val2);
  5036.     }
  5037.     else{
  5038.         if(v->user_val.p){
  5039.         if(*v->user_val.p){
  5040.             sprintf(prompt, "Your setting for %s is %s",
  5041.             v->name, v->user_val.p);
  5042.         }
  5043.         else{
  5044.             sprintf(prompt, "Your setting for %s is %s",
  5045.             v->name, empty_val2);
  5046.         }
  5047.         }
  5048.     }
  5049.     if(*prompt){
  5050.         if(strlen(prompt) > ps->ttyo->screen_cols - need)
  5051.           (void)strcpy(prompt + max(ps->ttyo->screen_cols - need - 3, 0),
  5052.               "...");
  5053.  
  5054.         (void)strcat(prompt, clear);
  5055.         if(want_to(prompt, 'y', 'n', NO_HELP, 0, 0) == 'y'){
  5056.         if(v->is_list){
  5057.             if(v->user_val.l){
  5058.             rv++;
  5059.             for(i = 0; v->user_val.l[i]; i++)
  5060.               fs_give((void **)&v->user_val.l[i]);
  5061.  
  5062.             fs_give((void **)&v->user_val.l);
  5063.             }
  5064.         }
  5065.         else if(v->user_val.p){
  5066.             rv++;
  5067.             fs_give((void **)&v->user_val.p);
  5068.         }
  5069.         }
  5070.     }
  5071.     }
  5072.  
  5073.     /*
  5074.      * As always, feature-list has to be handled separately.
  5075.      */
  5076.     v = &ps->vars[V_FEATURE_LIST];
  5077.     list = v->user_val.l;
  5078.     list_fixed = v->fixed_val.l;
  5079.     if(list){
  5080.       for(i = 0; list[i]; i++){
  5081.     p = list[i];
  5082.     if(!struncmp(p, "no-", 3))
  5083.       p += 3;
  5084.     for(k = 0; list_fixed && list_fixed[k]; k++){
  5085.       q = list_fixed[k];
  5086.       if(!struncmp(q, "no-", 3))
  5087.         q += 3;
  5088.       if(!strucmp(q, p)){
  5089.         sprintf(prompt, "Your %s is %s, fixed value is %s",
  5090.         p, p == list[i] ? "ON" : "OFF",
  5091.         q == list_fixed[k] ? "ON" : "OFF");
  5092.  
  5093.         if(strlen(prompt) > ps->ttyo->screen_cols - need)
  5094.           (void)strcpy(prompt + max(ps->ttyo->screen_cols - need - 3, 0),
  5095.               "...");
  5096.  
  5097.         (void)strcat(prompt, clear);
  5098.         if(want_to(prompt, 'y', 'n', NO_HELP, 0, 0) == 'y'){
  5099.         rv++;
  5100.         /*
  5101.          * Clear the feature from the user's pinerc
  5102.          * so that we'll stop bothering them when they
  5103.          * start up Pine.
  5104.          */
  5105.         clear_feature(&v->user_val.l, p);
  5106.  
  5107.         /*
  5108.          * clear_feature scoots the list up, so if list[i] was
  5109.          * the last one going in, now it is the end marker.  We
  5110.          * just decrement i so that it will get incremented and
  5111.          * then test == 0 in the for loop.  We could just goto
  5112.          * outta_here to accomplish the same thing.
  5113.          */
  5114.         if(!list[i])
  5115.           i--;
  5116.         }
  5117.       }
  5118.     }
  5119.       }
  5120.     }
  5121.  
  5122.     return(rv);
  5123. }
  5124.  
  5125.  
  5126. /*
  5127.  * Compare saved user_val with current user_val to see if it changed.
  5128.  * If any have changed, change it back and take the appropriate action.
  5129.  */
  5130. void
  5131. revert_to_saved_config(ps, vsave)
  5132. struct pine *ps;
  5133. SAVED_CONFIG_S *vsave;
  5134. {
  5135.     struct variable *vreal;
  5136.     SAVED_CONFIG_S  *v;
  5137.     int i, n;
  5138.  
  5139.     v = vsave;
  5140.     for(vreal = ps->vars; vreal->name; vreal++,v++){
  5141.     if(!SAVE_INCLUDE(ps, vreal))
  5142.       continue;
  5143.     
  5144.     if(vreal == &ps->vars[V_FEATURE_LIST]){
  5145.         /* handle feature changes */
  5146.         if(memcmp(v->user_val.features, ps->feature_list, BM_SIZE)){
  5147.         NAMEVAL_S *f;
  5148.  
  5149.         /*
  5150.          * At least one feature was changed.  Go through the
  5151.          * list of eligible features and toggle them back to what
  5152.          * they were.
  5153.          */
  5154.  
  5155.         for(i = 0; f = feature_list(i); i++){
  5156.             if(F_INCLUDE(f->value)
  5157.             && ((F_ON(f->value, ps)
  5158.                   && !bitnset(f->value,v->user_val.features))
  5159.                ||
  5160.                (F_OFF(f->value, ps)
  5161.                   && bitnset(f->value,v->user_val.features)))){
  5162.  
  5163.             toggle_feature_bit(ps, i, vreal, NULL);
  5164.             }
  5165.         }
  5166.         }
  5167.     }
  5168.     else{
  5169.         int changed = 0;
  5170.  
  5171.         if(vreal->is_list){
  5172.         if((v->user_val.l && !vreal->user_val.l)
  5173.            || (!v->user_val.l && vreal->user_val.l))
  5174.           changed++;
  5175.         else if(!v->user_val.l && !vreal->user_val.l)
  5176.           ;/* no change, nothing to do */
  5177.         else
  5178.           for(i = 0; v->user_val.l[i] || vreal->user_val.l[i]; i++)
  5179.             if((v->user_val.l[i]
  5180.               && (!vreal->user_val.l[i]
  5181.                  || strcmp(v->user_val.l[i], vreal->user_val.l[i])))
  5182.                ||
  5183.              (!v->user_val.l[i] && vreal->user_val.l[i])){
  5184.             changed++;
  5185.             break;
  5186.             }
  5187.         
  5188.         if(changed){
  5189.             char **list;
  5190.  
  5191.             /* free the changed value */
  5192.             if(vreal->user_val.l){
  5193.             for(i = 0; vreal->user_val.l[i]; i++)
  5194.               fs_give((void **)&vreal->user_val.l[i]);
  5195.             
  5196.             fs_give((void **)&vreal->user_val.l);
  5197.             }
  5198.  
  5199.             /* copy back the original one */
  5200.             if(v->user_val.l){
  5201.             list = v->user_val.l;
  5202.             n = 0;
  5203.             /* count how many */
  5204.             while(list[n])
  5205.               n++;
  5206.  
  5207.             vreal->user_val.l
  5208.                 = (char **)fs_get((n+1) * sizeof(char *));
  5209.             for(i = 0; i < n; i++)
  5210.               vreal->user_val.l[i] = cpystr(v->user_val.l[i]);
  5211.  
  5212.             vreal->user_val.l[n] = NULL;
  5213.             }
  5214.         }
  5215.         }
  5216.         else{
  5217.         if((v->user_val.p
  5218.               && (!vreal->user_val.p
  5219.               || strcmp(v->user_val.p, vreal->user_val.p)))
  5220.            ||
  5221.              (!v->user_val.p && vreal->user_val.p)){
  5222.             /* It changed, fix it */
  5223.             changed++;
  5224.             /* free the changed value */
  5225.             if(vreal->user_val.p)
  5226.               fs_give((void **)&vreal->user_val.p);
  5227.             
  5228.             /* copy back the original one */
  5229.             vreal->user_val.p = cpystr(v->user_val.p);
  5230.         }
  5231.         }
  5232.  
  5233.         if(changed){
  5234.         set_current_val(vreal, TRUE, FALSE);
  5235.         fix_side_effects(ps, vreal, 1);
  5236.         }
  5237.     }
  5238.     }
  5239. }
  5240.  
  5241.  
  5242. /*
  5243.  * Adjust side effects that happen because variable changes values.
  5244.  *
  5245.  * Var->user_val should be set to the new value before calling this.
  5246.  */
  5247. void
  5248. fix_side_effects(ps, var, revert)
  5249. struct pine     *ps;
  5250. struct variable *var;
  5251. int              revert;
  5252. {
  5253.     int    i;
  5254.     char **v, *q;
  5255.  
  5256.     /* move this up here so we get the Using default message */
  5257.     if(var == &ps->vars[V_PERSONAL_NAME]){
  5258.     if(!var->user_val.p && ps->ui.fullname){
  5259.         if(var->current_val.p)
  5260.           fs_give((void **)&var->current_val.p);
  5261.  
  5262.         var->current_val.p = cpystr(ps->ui.fullname);
  5263.     }
  5264.     }
  5265.  
  5266.     if(!revert
  5267.       && ((!var->is_fixed
  5268.         && !var->is_list
  5269.         && !var->user_val.p
  5270.         && var->current_val.p)
  5271.      ||
  5272.      (!var->is_fixed
  5273.         && var->is_list
  5274.         && !var->user_val.l
  5275.         && var->current_val.l)))
  5276.       q_status_message(SM_ORDER,0,3,"Using default value");
  5277.  
  5278.     if(var == &ps->vars[V_USER_DOMAIN]){
  5279.     char *p, *q;
  5280.  
  5281.     if(ps->VAR_USER_DOMAIN
  5282.        && ps->VAR_USER_DOMAIN[0]
  5283.        && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
  5284.         if(*(++p)){
  5285.         if(!revert)
  5286.           q_status_message2(SM_ORDER, 3, 5,
  5287.             "User-domain (%s) cannot contain \"@\"; using %s",
  5288.             ps->VAR_USER_DOMAIN, p);
  5289.         q = ps->VAR_USER_DOMAIN;
  5290.         while((*q++ = *p++) != '\0')
  5291.           ;/* do nothing */
  5292.         }
  5293.         else{
  5294.         if(!revert)
  5295.           q_status_message1(SM_ORDER, 3, 5,
  5296.             "User-domain (%s) cannot contain \"@\"; deleting",
  5297.             ps->VAR_USER_DOMAIN);
  5298.         fs_give((void **)&ps->USR_USER_DOMAIN);
  5299.         set_current_val(&ps->vars[V_USER_DOMAIN], TRUE, TRUE);
  5300.         }
  5301.     }
  5302.  
  5303.     /*
  5304.      * Reset various pointers pertaining to domain name and such...
  5305.      */
  5306.     init_hostname(ps);
  5307.     }
  5308.     else if(var == &ps->vars[V_INBOX_PATH]){
  5309.     /*
  5310.      * fixup the inbox path based on global/default values...
  5311.      */
  5312.     init_inbox_mapping(ps->VAR_INBOX_PATH, ps->context_list);
  5313.  
  5314.     if(!strucmp(ps->cur_folder, ps->inbox_name) && ps->mail_stream
  5315.        && strcmp(ps->VAR_INBOX_PATH, ps->mail_stream->mailbox)){
  5316.         /*
  5317.          * If we currently have "inbox" open and the mailbox name
  5318.          * doesn't match, reset the current folder's name...
  5319.          */
  5320.         strcpy(ps->cur_folder, ps->mail_stream->mailbox);
  5321.         ps->inbox_stream   = NULL;
  5322.         ps->mangled_header = 1;
  5323.     }
  5324.     else if(ps->inbox_stream
  5325.         && strcmp(ps->VAR_INBOX_PATH, ps->inbox_stream->mailbox)){
  5326.         /*
  5327.          * if we don't have inbox directly open, but have it
  5328.          * open for new mail notification, close the stream like
  5329.          * any other ordinary folder, and clean up...
  5330.          */
  5331.         MAILSTREAM *s = ps->inbox_stream;
  5332.         ps->inbox_stream = NULL;
  5333.         mn_give(&ps->inbox_msgmap);
  5334.         expunge_and_close(s, NULL, s->mailbox, NULL);
  5335.     }
  5336.     }
  5337.     else if(var == &ps->vars[V_FOLDER_SPEC]
  5338.        || var == &ps->vars[V_NEWS_SPEC]){
  5339.     if(!revert)
  5340.       q_status_message(SM_ORDER | SM_DING, 3, 4,
  5341.        "Folder List changes will take effect your next pine session.");
  5342.     }
  5343.     else if(var == &ps->vars[V_ADDRESSBOOK] ||
  5344.         var == &ps->vars[V_GLOB_ADDRBOOK] ||
  5345.         var == &ps->vars[V_ABOOK_FORMATS]){
  5346.     addrbook_reset();
  5347.     }
  5348.     else if(var == &ps->vars[V_INDEX_FORMAT]){
  5349.     init_index_format(ps->VAR_INDEX_FORMAT, &ps->index_disp_format);
  5350.     clear_index_cache();
  5351.     }
  5352.     else if(var == &ps->vars[V_DEFAULT_FCC]){
  5353.     init_save_defaults();
  5354.     }
  5355.     else if(var == &ps->vars[V_INIT_CMD_LIST]){
  5356.     if(!revert)
  5357.       q_status_message(SM_ASYNC, 0, 3,
  5358.         "Initial command changes will affect your next pine session.");
  5359.     }
  5360.     else if(var == &ps->vars[V_VIEW_HEADERS]){
  5361.     ps->view_all_except = 0;
  5362.     if(ps->VAR_VIEW_HEADERS)
  5363.       for(v = ps->VAR_VIEW_HEADERS; (q = *v) != NULL; v++)
  5364.         if(q[0]){
  5365.         char *p;
  5366.  
  5367.         removing_leading_white_space(q);
  5368.         /* look for colon or space or end */
  5369.         for(p = q; *p && !isspace((unsigned char)*p) && *p != ':'; p++)
  5370.           ;/* do nothing */
  5371.         
  5372.         *p = '\0';
  5373.         if(strucmp(q, ALL_EXCEPT) == 0)
  5374.           ps->view_all_except = 1;
  5375.         }
  5376.     }
  5377.     else if(var == &ps->vars[V_OVERLAP]){
  5378.     int old_value = ps->viewer_overlap;
  5379.  
  5380.     if(SVAR_OVERLAP(ps, old_value, tmp_20k_buf)){
  5381.         if(!revert)
  5382.           q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
  5383.     }
  5384.     else
  5385.       ps->viewer_overlap = old_value;
  5386.     }
  5387.     else if(var == &ps->vars[V_MARGIN]){
  5388.     int old_value = ps->scroll_margin;
  5389.  
  5390.     if(SVAR_MARGIN(ps, old_value, tmp_20k_buf)){
  5391.         if(!revert)
  5392.           q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
  5393.     }
  5394.     else
  5395.       ps->scroll_margin = old_value;
  5396.     }
  5397.     else if(var == &ps->vars[V_FILLCOL]){
  5398.     if(SVAR_FILLCOL(ps, ps->composer_fillcol, tmp_20k_buf)){
  5399.         if(!revert)
  5400.           q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
  5401.     }
  5402.     }
  5403.     else if(var == &ps->vars[V_STATUS_MSG_DELAY]){
  5404.     if(SVAR_MSGDLAY(ps, ps->status_msg_delay, tmp_20k_buf)){
  5405.         if(!revert)
  5406.           q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
  5407.     }
  5408.     }
  5409.     else if(var == &ps->vars[V_MAILCHECK]){
  5410.     timeout = 15;
  5411.     if(SVAR_MAILCHK(ps, timeout, tmp_20k_buf)){
  5412.         if(!revert)
  5413.           q_status_message(SM_ORDER, 3, 5, tmp_20k_buf);
  5414.     }
  5415.     else if(timeout == 0L && !revert){
  5416.         q_status_message(SM_ORDER, 4, 6,
  5417. "Warning: automatic new mail checking and mailbox checkpointing is disabled");
  5418.         if(ps->VAR_INBOX_PATH && ps->VAR_INBOX_PATH[0] == '{')
  5419.           q_status_message(SM_ASYNC, 3, 6,
  5420. "Warning: mail-check-interval=0 may cause IMAP server connection to time out");
  5421.     }
  5422.     }
  5423. #if defined(DOS) || defined(OS2)
  5424.     else if(var == &ps->vars[V_FOLDER_EXTENSION]){
  5425.     mail_parameters(NULL, SET_EXTENSION,
  5426.             (void *)var->current_val.p);
  5427.     }
  5428.     else if(var == &ps->vars[V_NEWSRC_PATH]){
  5429.     if(var->current_val.p && var->current_val.p[0])
  5430.       mail_parameters(NULL, SET_NEWSRC,
  5431.               (void *)var->current_val.p);
  5432.     }
  5433. #endif
  5434.     else if(revert
  5435.       && (var == &ps->vars[V_SAVED_MSG_NAME_RULE]
  5436.               || var == &ps->vars[V_FCC_RULE]
  5437.               || var == &ps->vars[V_GOTO_DEFAULT_RULE]
  5438.               || var == &ps->vars[V_AB_SORT_RULE])){
  5439.     NAMEVAL_S *rule;
  5440.  
  5441.     if(var == &ps->vars[V_SAVED_MSG_NAME_RULE]){
  5442.         for(i = 0; rule = save_msg_rules(i); i++)
  5443.           if(!strucmp(var->user_val.p, rule->name)){
  5444.           ps->save_msg_rule = rule->value;
  5445.           break;
  5446.           }
  5447.     }
  5448.     else if(var == &ps->vars[V_FCC_RULE]){
  5449.         for(i = 0; rule = fcc_rules(i); i++)
  5450.           if(!strucmp(var->user_val.p, rule->name)){
  5451.           ps->fcc_rule = rule->value;
  5452.           break;
  5453.           }
  5454.     }
  5455.     else if(var == &ps->vars[V_GOTO_DEFAULT_RULE]){
  5456.         for(i = 0; rule = goto_rules(i); i++)
  5457.           if(!strucmp(var->user_val.p, rule->name)){
  5458.           ps->goto_default_rule = rule->value;
  5459.           break;
  5460.           }
  5461.     }
  5462.     else{
  5463.         for(i = 0; rule = ab_sort_rules(i); i++)
  5464.           if(!strucmp(var->user_val.p, rule->name)){
  5465.           ps->ab_sort_rule = rule->value;
  5466.           break;
  5467.           }
  5468.  
  5469.         addrbook_reset();
  5470.     }
  5471.     }
  5472.     else if(revert && var == &ps->vars[V_SORT_KEY]){
  5473.     decode_sort(ps, var->user_val.p);
  5474.     }
  5475. #if defined(DOS) || defined(OS2)
  5476.     else if(revert
  5477.        && (var == &ps->vars[V_NORM_FORE_COLOR]
  5478.         || var == &ps->vars[V_NORM_BACK_COLOR]
  5479.         || var == &ps->vars[V_REV_FORE_COLOR]
  5480.         || var == &ps->vars[V_REV_BACK_COLOR])){
  5481.     if(var == &ps->vars[V_NORM_FORE_COLOR])
  5482.       pico_nfcolor(var->user_val.p);
  5483.     else if(var == &ps->vars[V_NORM_BACK_COLOR])
  5484.       pico_nbcolor(var->user_val.p);
  5485.     else if(var == &ps->vars[V_REV_FORE_COLOR])
  5486.       pico_rfcolor(var->user_val.p);
  5487.     else
  5488.       pico_rbcolor(var->user_val.p);
  5489.     }
  5490. #endif
  5491.     else if(var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
  5492.     init_hostname(ps);
  5493.     }
  5494. }
  5495.  
  5496.  
  5497. SAVED_CONFIG_S *
  5498. save_config_vars(ps)
  5499. struct pine *ps;
  5500. {
  5501.     struct variable *vreal;
  5502.     SAVED_CONFIG_S *vsave, *v;
  5503.  
  5504.     vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
  5505.     memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
  5506.     v = vsave;
  5507.     for(vreal = ps->vars; vreal->name; vreal++,v++){
  5508.     if(!SAVE_INCLUDE(ps, vreal))
  5509.       continue;
  5510.     
  5511.     if(vreal == &ps->vars[V_FEATURE_LIST]){
  5512.         /* save copy of feature bitmap */
  5513.         memcpy(v->user_val.features, ps->feature_list, BM_SIZE);
  5514.     }
  5515.     else if(vreal->is_list){  /* save user_val.l */
  5516.         int n, i;
  5517.         char **list;
  5518.  
  5519.         if(vreal->user_val.l){
  5520.         /* count how many */
  5521.         n = 0;
  5522.         list = vreal->user_val.l;
  5523.         while(list[n])
  5524.           n++;
  5525.  
  5526.         v->user_val.l = (char **)fs_get((n+1) * sizeof(char *));
  5527.         memset((void *)v->user_val.l, 0, (n+1)*sizeof(char *));
  5528.         for(i = 0; i < n; i++)
  5529.           v->user_val.l[i] = cpystr(vreal->user_val.l[i]);
  5530.  
  5531.         v->user_val.l[n] = NULL;
  5532.         }
  5533.     }
  5534.     else{  /* save user_val.p */
  5535.         if(vreal->user_val.p)
  5536.           v->user_val.p = cpystr(vreal->user_val.p);
  5537.     }
  5538.     }
  5539.  
  5540.     return(vsave);
  5541. }
  5542.  
  5543.  
  5544. void
  5545. free_saved_config(ps, vsavep)
  5546. struct pine *ps;
  5547. SAVED_CONFIG_S **vsavep;
  5548. {
  5549.     struct variable *vreal;
  5550.     SAVED_CONFIG_S *v;
  5551.  
  5552.     v = *vsavep;
  5553.     for(vreal = ps->vars; vreal->name; vreal++,v++){
  5554.     if(!SAVE_INCLUDE(ps, vreal))
  5555.       continue;
  5556.     
  5557.     if(vreal == &ps->vars[V_FEATURE_LIST]) /* nothing to free */
  5558.       continue;
  5559.  
  5560.     if(vreal->is_list){  /* free user_val.l */
  5561.         int i;
  5562.  
  5563.         if(v->user_val.l){
  5564.         for(i = 0; v->user_val.l[i]; i++)
  5565.               fs_give((void **)&v->user_val.l[i]);
  5566.  
  5567.             fs_give((void **)&v->user_val.l);
  5568.         }
  5569.     }
  5570.     else if(v->user_val.p)
  5571.       fs_give((void **)&v->user_val.p);
  5572.     }
  5573.  
  5574.     fs_give((void **)vsavep);
  5575. }
  5576.  
  5577.  
  5578. /*
  5579.  * Given a single printer string from the config file, returns pointers
  5580.  * to alloc'd strings containing the printer nickname, the command,
  5581.  * the init string, the trailer string, everything but the nickname string,
  5582.  * and everything but the command string.  All_but_cmd includes the trailing
  5583.  * space at the end (the one before the command) but all_but_nick does not
  5584.  * include the leading space (the one before the [).
  5585.  * If you pass in a pointer it is guaranteed to come back pointing to an
  5586.  * allocated string, even if it is just an empty string.  It is ok to pass
  5587.  * NULL for any of the six return strings.
  5588.  */
  5589. void
  5590. parse_printer(input, nick, cmd, init, trailer, all_but_nick, all_but_cmd)
  5591.     char  *input;
  5592.     char **nick,
  5593.      **cmd,
  5594.      **init,
  5595.      **trailer,
  5596.      **all_but_nick,
  5597.      **all_but_cmd;
  5598. {
  5599.     char *p, *q, *start, *saved_options = NULL;
  5600.     int tmpsave, cnt;
  5601.  
  5602.     if(!input)
  5603.       input = "";
  5604.  
  5605.     if(nick || all_but_nick){
  5606.     if(p = srchstr(input, " [")){
  5607.         if(all_but_nick)
  5608.           *all_but_nick = cpystr(p+1);
  5609.  
  5610.         if(nick){
  5611.         while(p-1 > input && isspace((unsigned char)*(p-1)))
  5612.           p--;
  5613.  
  5614.         tmpsave = *p;
  5615.         *p = '\0';
  5616.         *nick = cpystr(input);
  5617.         *p = tmpsave;
  5618.         }
  5619.     }
  5620.     else{
  5621.         if(nick)
  5622.           *nick = cpystr("");
  5623.  
  5624.         if(all_but_nick)
  5625.           *all_but_nick = cpystr(input);
  5626.     }
  5627.     }
  5628.  
  5629.     if(p = srchstr(input, "] ")){
  5630.     do{
  5631.         ++p;
  5632.     }while(isspace((unsigned char)*p));
  5633.  
  5634.     tmpsave = *p;
  5635.     *p = '\0';
  5636.     saved_options = cpystr(input);
  5637.     *p = tmpsave;
  5638.     }
  5639.     else
  5640.       p = input;
  5641.     
  5642.     if(cmd)
  5643.       *cmd = cpystr(p);
  5644.  
  5645.     if(init){
  5646.     if(saved_options && (p = srchstr(saved_options, "INIT="))){
  5647.         start = p + strlen("INIT=");
  5648.         for(cnt=0, p = start;
  5649.         *p && *(p+1) && isxdigit((unsigned char)*p)
  5650.            && isxdigit((unsigned char)*(p+1));
  5651.         p += 2)
  5652.           cnt++;
  5653.         
  5654.         q = *init = (char *)fs_get((cnt + 1) * sizeof(char));
  5655.         for(p = start;
  5656.         *p && *(p+1) && isxdigit((unsigned char)*p)
  5657.            && isxdigit((unsigned char)*(p+1));
  5658.         p += 2)
  5659.           *q++ = read_hex(p);
  5660.         
  5661.         *q = '\0';
  5662.     }
  5663.     else
  5664.       *init = cpystr("");
  5665.     }
  5666.  
  5667.     if(trailer){
  5668.     if(saved_options && (p = srchstr(saved_options, "TRAILER="))){
  5669.         start = p + strlen("TRAILER=");
  5670.         for(cnt=0, p = start;
  5671.         *p && *(p+1) && isxdigit((unsigned char)*p)
  5672.            && isxdigit((unsigned char)*(p+1));
  5673.         p += 2)
  5674.           cnt++;
  5675.         
  5676.         q = *trailer = (char *)fs_get((cnt + 1) * sizeof(char));
  5677.         for(p = start;
  5678.         *p && *(p+1) && isxdigit((unsigned char)*p)
  5679.            && isxdigit((unsigned char)*(p+1));
  5680.         p += 2)
  5681.           *q++ = read_hex(p);
  5682.         
  5683.         *q = '\0';
  5684.     }
  5685.     else
  5686.       *trailer = cpystr("");
  5687.     }
  5688.  
  5689.     if(all_but_cmd){
  5690.     if(saved_options)
  5691.       *all_but_cmd = saved_options;
  5692.     else
  5693.       *all_but_cmd = cpystr("");
  5694.     }
  5695.     else if(saved_options)
  5696.       fs_give((void **)&saved_options);
  5697. }
  5698.  
  5699.  
  5700. /*
  5701.  * Given a single printer string from the config file, returns an allocated
  5702.  * copy of the friendly printer name, which is
  5703.  *      "Nickname"  command
  5704.  */
  5705. char *
  5706. printer_name(input)
  5707.     char *input;
  5708. {
  5709.     char *nick, *cmd;
  5710.     char *ret;
  5711.  
  5712.     parse_printer(input, &nick, &cmd, NULL, NULL, NULL, NULL);
  5713.     ret = (char *)fs_get((2+22+1+strlen(cmd)) * sizeof(char));
  5714.     sprintf(ret, "\"%.21s\"%*s%s",
  5715.     *nick ? nick : "",
  5716.     22 - min(strlen(nick), 21),
  5717.     "",
  5718.     cmd);
  5719.     fs_give((void **)&nick);
  5720.     fs_give((void **)&cmd);
  5721.  
  5722.     return(ret);
  5723. }
  5724.  
  5725.  
  5726. #ifdef _WINDOWS
  5727. /*----------------------------------------------------------------------
  5728.      MSWin scroll callback.  Called during scroll message processing.
  5729.          
  5730.  
  5731.  
  5732.   Args: cmd - what type of scroll operation.
  5733.     scroll_pos - paramter for operation.  
  5734.             used as position for SCROLL_TO operation.
  5735.  
  5736.   Returns: TRUE - did the scroll operation.
  5737.        FALSE - was not able to do the scroll operation.
  5738.  ----*/
  5739. int
  5740. config_scroll_callback (cmd, scroll_pos)
  5741. int    cmd;
  5742. long    scroll_pos;
  5743. {
  5744.     int paint = TRUE;
  5745.     
  5746.     switch (cmd) {
  5747.       case MSWIN_KEY_SCROLLUPLINE:
  5748.     paint = config_scroll_down (1);
  5749.     break;
  5750.  
  5751.       case MSWIN_KEY_SCROLLDOWNLINE:
  5752.     paint = config_scroll_up (1);
  5753.     break;
  5754.  
  5755.       case MSWIN_KEY_SCROLLUPPAGE:
  5756.     paint = config_scroll_down (BODY_LINES(ps_global));
  5757.     break;
  5758.  
  5759.       case MSWIN_KEY_SCROLLDOWNPAGE:
  5760.     paint = config_scroll_up (BODY_LINES(ps_global));
  5761.     break;
  5762.  
  5763.       case MSWIN_KEY_SCROLLTO:
  5764.     paint = config_scroll_to_pos (scroll_pos);
  5765.     break;
  5766.     }
  5767.  
  5768.     if(paint){
  5769.     option_screen_redrawer();
  5770.     fflush(stdout);
  5771.     }
  5772.  
  5773.     return(paint);
  5774. }
  5775. #endif    /* _WINDOWS */
  5776.  
  5777.  
  5778. static struct key gripe_keys[] = 
  5779.        {{"?","Help",KS_SCREENHELP},    {"^C","Cancel",KS_NONE},
  5780.     {NULL,NULL,KS_NONE},            {"S",NULL,KS_NONE},
  5781.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  5782.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  5783.     {NULL,NULL,KS_NONE},            {NULL,NULL,KS_NONE},
  5784.     {NULL,NULL,KS_NONE},            {"W","WhereIs",KS_WHEREIS}};
  5785. INST_KEY_MENU(gripe_keymenu, gripe_keys);
  5786. #define SELECT_KEY 3
  5787.  
  5788.  
  5789. /*----------------------------------------------------------------------
  5790.     Bug report screen
  5791.  ----*/
  5792. void
  5793. gripe(ps) 
  5794.     struct pine *ps;
  5795. {
  5796.     CONF_S  *ctmpb, *heading, *start_line, *ctmpa = NULL;
  5797.  
  5798.     if(F_ON(F_DISABLE_DFLT_IN_BUG_RPT,ps_global))
  5799.       gripe_keys[SELECT_KEY].label = "Select";
  5800.     else
  5801.       gripe_keys[SELECT_KEY].label = "[Select]";
  5802.  
  5803.     new_confline(&ctmpa);
  5804.     heading = ctmpa;
  5805.     ctmpa->varoffset = 10;
  5806.     ctmpa->keymenu   = &gripe_keymenu;
  5807.     ctmpa->help      = NO_HELP;
  5808.     ctmpa->tool      = gripe_tool;
  5809.     ctmpa->flags    |= CF_NOSELECT;
  5810.     ctmpa->varname
  5811.       = cpystr("Reporting a bug:  choose one of the following options...");
  5812.     ctmpa->value     = NULL;
  5813.  
  5814.     new_confline(&ctmpa);
  5815.     ctmpa->valoffset = 0;
  5816.     ctmpa->keymenu   = &gripe_keymenu;
  5817.     ctmpa->help      = NO_HELP;
  5818.     ctmpa->tool      = gripe_tool;
  5819.     ctmpa->flags    |= CF_NOSELECT;
  5820.     ctmpa->value
  5821.       = cpystr("");
  5822.  
  5823.  
  5824.     new_confline(&ctmpa);
  5825.     start_line = ctmpb = ctmpa;
  5826.     ctmpa->valoffset = 1;
  5827.     ctmpa->keymenu   = &gripe_keymenu;
  5828.     ctmpa->help      = NO_HELP;
  5829.     ctmpa->tool      = gripe_tool;
  5830.     ctmpa->varname   = cpystr("L");
  5831.     ctmpa->flags    |= CF_INVISIBLEVAR;
  5832.     ctmpa->value
  5833.       = cpystr("o  Send a question to your local support staff.");
  5834.     ctmpa->varnamep  = ctmpb;
  5835.     ctmpa->headingp  = heading;
  5836.  
  5837.     new_confline(&ctmpa);
  5838.     ctmpa->valoffset = 4;
  5839.     ctmpa->keymenu   = &gripe_keymenu;
  5840.     ctmpa->help      = NO_HELP;
  5841.     ctmpa->tool      = gripe_tool;
  5842.     ctmpa->flags    |= CF_NOSELECT;
  5843.     ctmpa->value
  5844.       = cpystr("If you have a question about how Pine works, or how some other aspect");
  5845.  
  5846.     new_confline(&ctmpa);
  5847.     ctmpa->valoffset = 4;
  5848.     ctmpa->keymenu   = &gripe_keymenu;
  5849.     ctmpa->help      = NO_HELP;
  5850.     ctmpa->tool      = gripe_tool;
  5851.     ctmpa->flags    |= CF_NOSELECT;
  5852.     ctmpa->value
  5853.       = cpystr("of your computer system works, it is probably best if you ask your local");
  5854.  
  5855.     new_confline(&ctmpa);
  5856.     ctmpa->valoffset = 4;
  5857.     ctmpa->keymenu   = &gripe_keymenu;
  5858.     ctmpa->help      = NO_HELP;
  5859.     ctmpa->tool      = gripe_tool;
  5860.     ctmpa->flags    |= CF_NOSELECT;
  5861.     ctmpa->value
  5862.       = cpystr("support staff.  They are likely to be able to answer more quickly than");
  5863.  
  5864.     new_confline(&ctmpa);
  5865.     ctmpa->valoffset = 4;
  5866.     ctmpa->keymenu   = &gripe_keymenu;
  5867.     ctmpa->help      = NO_HELP;
  5868.     ctmpa->tool      = gripe_tool;
  5869.     ctmpa->flags    |= CF_NOSELECT;
  5870.     ctmpa->value
  5871.       = cpystr("the U.W. Pine development team, and they know much more about their system.");
  5872.  
  5873.     new_confline(&ctmpa);
  5874.     ctmpa->valoffset = 0;
  5875.     ctmpa->keymenu   = &gripe_keymenu;
  5876.     ctmpa->help      = NO_HELP;
  5877.     ctmpa->tool      = gripe_tool;
  5878.     ctmpa->flags    |= CF_NOSELECT;
  5879.     ctmpa->value
  5880.       = cpystr("");
  5881.  
  5882.  
  5883.     new_confline(&ctmpa);
  5884.     ctmpb = ctmpa;
  5885.     ctmpa->valoffset = 1;
  5886.     ctmpa->keymenu   = &gripe_keymenu;
  5887.     ctmpa->help      = NO_HELP;
  5888.     ctmpa->tool      = gripe_tool;
  5889.     ctmpa->varoffset = 1;
  5890.     ctmpa->varname   = cpystr("B");
  5891.     ctmpa->flags    |= CF_INVISIBLEVAR;
  5892.     ctmpa->value
  5893.       = cpystr("o  Send a bug report to the Pine development team at the Univ. of Wash.");
  5894.     ctmpa->varnamep  = ctmpb;
  5895.     ctmpa->headingp  = heading;
  5896.  
  5897.     new_confline(&ctmpa);
  5898.     ctmpa->valoffset = 4;
  5899.     ctmpa->keymenu   = &gripe_keymenu;
  5900.     ctmpa->help      = NO_HELP;
  5901.     ctmpa->tool      = gripe_tool;
  5902.     ctmpa->flags    |= CF_NOSELECT;
  5903.     ctmpa->value
  5904.       = cpystr("The more precise a description you give the more likely");
  5905.  
  5906.     new_confline(&ctmpa);
  5907.     ctmpa->valoffset = 4;
  5908.     ctmpa->keymenu   = &gripe_keymenu;
  5909.     ctmpa->help      = NO_HELP;
  5910.     ctmpa->tool      = gripe_tool;
  5911.     ctmpa->flags    |= CF_NOSELECT;
  5912.     ctmpa->value
  5913.       = cpystr("we'll be able to fix it for the next release.  Best of all is a way");
  5914.  
  5915.     new_confline(&ctmpa);
  5916.     ctmpa->valoffset = 4;
  5917.     ctmpa->keymenu   = &gripe_keymenu;
  5918.     ctmpa->help      = NO_HELP;
  5919.     ctmpa->tool      = gripe_tool;
  5920.     ctmpa->flags    |= CF_NOSELECT;
  5921.     ctmpa->value
  5922.       = cpystr("to reproduce the problem, if you know of one, but we also want to know");
  5923.  
  5924.     new_confline(&ctmpa);
  5925.     ctmpa->valoffset = 4;
  5926.     ctmpa->keymenu   = &gripe_keymenu;
  5927.     ctmpa->help      = NO_HELP;
  5928.     ctmpa->tool      = gripe_tool;
  5929.     ctmpa->flags    |= CF_NOSELECT;
  5930.     ctmpa->value
  5931.       = cpystr("about unreproducible bugs.");
  5932.  
  5933.     new_confline(&ctmpa);
  5934.     ctmpa->valoffset = 0;
  5935.     ctmpa->keymenu   = &gripe_keymenu;
  5936.     ctmpa->help      = NO_HELP;
  5937.     ctmpa->tool      = gripe_tool;
  5938.     ctmpa->flags    |= CF_NOSELECT;
  5939.     ctmpa->value
  5940.       = cpystr("");
  5941.  
  5942.     new_confline(&ctmpa);
  5943.     ctmpb = ctmpa;
  5944.     ctmpa->valoffset = 1;
  5945.     ctmpa->keymenu   = &gripe_keymenu;
  5946.     ctmpa->help      = NO_HELP;
  5947.     ctmpa->tool      = gripe_tool;
  5948.     ctmpa->varoffset = 1;
  5949.     ctmpa->varname   = cpystr("S");
  5950.     ctmpa->flags    |= CF_INVISIBLEVAR;
  5951.     ctmpa->value
  5952.       = cpystr("o  Send a suggestion to the Pine development team at the Univ. of Wash.");
  5953.     ctmpa->varnamep  = ctmpb;
  5954.     ctmpa->headingp  = heading;
  5955.  
  5956.     new_confline(&ctmpa);
  5957.     ctmpa->valoffset = 4;
  5958.     ctmpa->keymenu   = &gripe_keymenu;
  5959.     ctmpa->help      = NO_HELP;
  5960.     ctmpa->tool      = gripe_tool;
  5961.     ctmpa->flags    |= CF_NOSELECT;
  5962.     ctmpa->value
  5963.       = cpystr("");
  5964.  
  5965.     new_confline(&ctmpa);
  5966.     ctmpa->valoffset = 2;
  5967.     ctmpa->keymenu   = &gripe_keymenu;
  5968.     ctmpa->help      = NO_HELP;
  5969.     ctmpa->tool      = gripe_tool;
  5970.     ctmpa->flags    |= CF_NOSELECT;
  5971.     ctmpa->value
  5972.       = cpystr("...or, use \"Compose\" to post a message to \"pine-info@cac.washington.edu\", a");
  5973.  
  5974.     new_confline(&ctmpa);
  5975.     ctmpa->valoffset = 4;
  5976.     ctmpa->keymenu   = &gripe_keymenu;
  5977.     ctmpa->help      = NO_HELP;
  5978.     ctmpa->tool      = gripe_tool;
  5979.     ctmpa->flags    |= CF_NOSELECT;
  5980.     ctmpa->value
  5981.       = cpystr("world-wide mailing-list read by thousands of Pine users and administrators.");
  5982.  
  5983.     (void)conf_scroll_screen(ps, start_line, "BUG REPORT", NoPrint);
  5984. }
  5985.  
  5986.  
  5987. /*
  5988.  * standard type of storage object used for body parts...
  5989.  */
  5990. #ifdef    DOS
  5991. #define          PART_SO_TYPE    TmpFileStar
  5992. #else
  5993. #define          PART_SO_TYPE    CharStar
  5994. #endif
  5995.  
  5996. int
  5997. gripe_tool(ps, cmd, cl, flags)
  5998.     struct pine *ps;
  5999.     int          cmd;
  6000.     CONF_S     **cl;
  6001.     unsigned     flags;
  6002. {
  6003.     BODY      *body = NULL, *pb;
  6004.     ENVELOPE  *outgoing = NULL;
  6005.     PART     **pp;
  6006.     gf_io_t    pc;
  6007.     char       tmp[MAX_ADDRESS], *p, *sig;
  6008.     int           i, ch = 0, ourcmd;
  6009.     char       composer_title[80];
  6010.     long       fake_reply = -1L,
  6011.            msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
  6012.     static char *err    = "Problem creating space for message text.";
  6013.  
  6014.     ourcmd = 'X';
  6015.     switch(cmd){
  6016.       case ctrl('C'):
  6017.       case PF2:
  6018.       default:  /* cancel on bad input to reduce accidental bug reports */
  6019.     break;
  6020.  
  6021.       case 's':
  6022.       case PF4:
  6023.       case ctrl('M'):
  6024.       case ctrl('J'):
  6025.     if(F_ON(F_DISABLE_DFLT_IN_BUG_RPT,ps_global)
  6026.        && (cmd == ctrl('M') || cmd == ctrl('J')))
  6027.       break;
  6028.  
  6029.     if(cl && *cl && (*cl)->varname)
  6030.       ourcmd = (*cl)->varname[0];
  6031.     
  6032.     break;
  6033.     }
  6034.  
  6035.     switch(ourcmd){
  6036.       case 'X':
  6037.     q_status_message(SM_ORDER, 0, 3, "Bug report cancelled.");
  6038.     goto bomb;
  6039.  
  6040.       case 'B':
  6041.     if(!ps->VAR_BUGS_ADDRESS){
  6042.         q_status_message(SM_ORDER, 3, 3,
  6043.         "Bug report cancelled: no bug address configured.");
  6044.         goto bomb;
  6045.     }
  6046.  
  6047.     sprintf(tmp, "%s%s%s%s%s",
  6048.         ps->VAR_BUGS_FULLNAME ? "\"" : "",
  6049.         ps->VAR_BUGS_FULLNAME ? ps->VAR_BUGS_FULLNAME : "",
  6050.         ps->VAR_BUGS_FULLNAME ? "\" <" : "",
  6051.         ps->VAR_BUGS_ADDRESS,
  6052.         ps->VAR_BUGS_FULLNAME ? ">" : "");
  6053.  
  6054.     strcpy(composer_title, "COMPOSE BUG REPORT");
  6055.     dprint(1, (debugfile, "\n\n    -- REPORTING BUG(%s) --\n", tmp));
  6056.     break;
  6057.  
  6058.       case 'S':
  6059.     if(!ps->VAR_SUGGEST_ADDRESS){
  6060.         q_status_message(SM_ORDER, 3, 3,
  6061.         "Suggestion cancelled: no suggestion address configured.");
  6062.         goto bomb;
  6063.     }
  6064.  
  6065.     sprintf(tmp, "%s%s%s%s%s",
  6066.         ps->VAR_SUGGEST_FULLNAME ? "\"" : "",
  6067.         ps->VAR_SUGGEST_FULLNAME ? ps->VAR_SUGGEST_FULLNAME : "",
  6068.         ps->VAR_SUGGEST_FULLNAME ? "\" <" : "",
  6069.         ps->VAR_SUGGEST_ADDRESS,
  6070.         ps->VAR_SUGGEST_FULLNAME ? ">" : "");
  6071.  
  6072.     strcpy(composer_title, "COMPOSE SUGGESTION");
  6073.     dprint(1, (debugfile, "\n\n    -- Sending suggestion(%s) --\n", tmp));
  6074.     break;
  6075.  
  6076.       case 'L':
  6077.     if(!ps->VAR_LOCAL_ADDRESS){
  6078.         q_status_message(SM_ORDER, 3, 3,
  6079.         "Cancelled: no local support address configured.");
  6080.         goto bomb;
  6081.     }
  6082.  
  6083.     sprintf(tmp, "%s%s%s%s%s",
  6084.         ps->VAR_LOCAL_FULLNAME ? "\"" : "",
  6085.         ps->VAR_LOCAL_FULLNAME ? ps->VAR_LOCAL_FULLNAME : "",
  6086.         ps->VAR_LOCAL_FULLNAME ? "\" <" : "",
  6087.         ps->VAR_LOCAL_ADDRESS,
  6088.         ps->VAR_LOCAL_FULLNAME ? ">" : "");
  6089.  
  6090.     strcpy(composer_title, "COMPOSE TO LOCAL SUPPORT");
  6091.     dprint(1, (debugfile, "\n\n   -- Send to local support(%s) --\n", tmp));
  6092.     break;
  6093.     
  6094.       default:
  6095.     break;
  6096.     }
  6097.  
  6098.     outgoing = mail_newenvelope();
  6099.     rfc822_parse_adrlist(&outgoing->to, tmp, ps->maildomain);
  6100.     outgoing->message_id = generate_message_id(ps);
  6101.  
  6102.     /*
  6103.      * Build our contribution to the subject; part constant string
  6104.      * and random 4 character alpha numeric string.
  6105.      */
  6106.     tmp_20k_buf[0] = '\0';
  6107.     if(ourcmd == 'B' || ourcmd == 'S')
  6108.     sprintf(tmp_20k_buf, "%cug (ID %c%c%d%c%c): ", ourcmd,
  6109.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10),
  6110.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10),
  6111.         (int)(random() % 10L),
  6112.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10),
  6113.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10));
  6114.     outgoing->subject = cpystr(tmp_20k_buf);
  6115.  
  6116.     body       = mail_newbody();
  6117.  
  6118.     if(ourcmd != 'B'){
  6119.     body->type = TYPETEXT;
  6120.     /* Allocate an object for the body */
  6121.     if(body->contents.binary=(void *)so_get(PicoText,NULL,EDIT_ACCESS)){
  6122.         if((sig = get_signature()) && *sig){
  6123.         so_puts((STORE_S *)body->contents.binary, sig);
  6124.         fs_give((void **)&sig);
  6125.         }
  6126.     }
  6127.     else{
  6128.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6129.         goto bomb;
  6130.     }
  6131.     }
  6132.     else{  /* ourcmd == 'B' */
  6133.     body->type = TYPEMULTIPART;
  6134.     /*---- The TEXT part/body ----*/
  6135.     body->contents.part            = mail_newbody_part();
  6136.     body->contents.part->body.type = TYPETEXT;
  6137.     /* Allocate an object for the body */
  6138.     if(body->contents.part->body.contents.binary = 
  6139.                     (void *)so_get(PicoText,NULL,EDIT_ACCESS)){
  6140.         pp = &(body->contents.part->next);
  6141.         if((sig = get_signature()) && *sig){
  6142.         so_puts((STORE_S *)body->contents.part->body.contents.binary,
  6143.             sig);
  6144.         fs_give((void **)&sig);
  6145.         }
  6146.     }
  6147.     else{
  6148.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6149.         goto bomb;
  6150.     }
  6151.  
  6152.     /*---- create object, and write current config into it ----*/
  6153.     *pp                 = mail_newbody_part();
  6154.     pb                 = &((*pp)->body);
  6155.     pp                 = &((*pp)->next);
  6156.     pb->type             = TYPETEXT;
  6157.     pb->id             = generate_message_id(ps);
  6158.     pb->description          = cpystr("Pine Configuration Data");
  6159.     pb->parameter         = mail_newbody_parameter();
  6160.     pb->parameter->attribute = cpystr("name");
  6161.     pb->parameter->value     = cpystr("config.txt");
  6162.     pb->contents.msg.env     = NULL;
  6163.     pb->contents.msg.body    = NULL;
  6164.  
  6165.     if(pb->contents.binary = (void *) so_get(CharStar, NULL, EDIT_ACCESS)){
  6166.         extern char datestamp[], hoststamp[];
  6167.  
  6168.         gf_set_so_writec(&pc, (STORE_S *)pb->contents.binary);
  6169.         gf_puts("Pine built ", pc);
  6170.         gf_puts(datestamp, pc);
  6171.         gf_puts(" on host: ", pc);
  6172.         gf_puts(hoststamp, pc);
  6173.         gf_puts("\n", pc);
  6174.         dump_pine_struct(ps, pc);
  6175.         dump_config(ps, pc);
  6176.         /* dump last n keystrokes */
  6177.         gf_puts("========== Latest keystrokes ==========\n", pc);
  6178.         while((i = key_recorder(0, 1)) != -1){
  6179.         sprintf(tmp, "\t%s\t(0x%04.4x)\n", pretty_command(i), i);
  6180.         gf_puts(tmp, pc);
  6181.         }
  6182.  
  6183.         pb->size.bytes = strlen((char *)so_text(
  6184.                           (STORE_S *)pb->contents.binary));
  6185.     }
  6186.     else{
  6187.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6188.         goto bomb;
  6189.     }
  6190.  
  6191.     /* check for local debugging info */
  6192.     if(ps_global->VAR_BUGS_EXTRAS
  6193.        && can_access(ps_global->VAR_BUGS_EXTRAS, EXECUTE_ACCESS) == 0){
  6194.         char *error             = NULL;
  6195.         *pp                 = mail_newbody_part();
  6196.         pb                 = &((*pp)->body);
  6197.         pb->type             = TYPETEXT;
  6198.         pb->id                 = generate_message_id(ps);
  6199.         pb->description             = cpystr("Local Configuration Data");
  6200.         pb->parameter             = mail_newbody_parameter();
  6201.         pb->parameter->attribute = cpystr("name");
  6202.         pb->parameter->value     = cpystr("lconfig.txt");
  6203.         pb->contents.msg.env     = NULL;
  6204.         pb->contents.msg.body    = NULL;
  6205.  
  6206.         if(pb->contents.binary =
  6207.                 (void *) so_get(CharStar, NULL, EDIT_ACCESS)){
  6208.         PIPE_S  *syspipe;
  6209.         gf_io_t  gc;
  6210.  
  6211.         gf_set_so_writec(&pc, (STORE_S *)pb->contents.binary);
  6212.         if(syspipe = open_system_pipe(ps_global->VAR_BUGS_EXTRAS,
  6213.                      NULL, NULL,
  6214.                      PIPE_READ | PIPE_STDERR | PIPE_USER)){
  6215.             gf_set_readc(&gc, (void *)syspipe->in.f, 0, FileStar);
  6216.             gf_filter_init();
  6217.             error = gf_pipe(gc, pc);
  6218.             (void) close_system_pipe(&syspipe);
  6219.         }
  6220.         else
  6221.           error = "executing config collector";
  6222.         }
  6223.  
  6224.         if(error){
  6225.         q_status_message1(SM_ORDER | SM_DING, 3, 4,
  6226.                   "Problem %s", error);
  6227.         goto bomb;
  6228.         }
  6229.         else            /* fixup attachment's size */
  6230.           pb->size.bytes = strlen((char *)so_text(
  6231.                       (STORE_S *)pb->contents.binary));
  6232.     }
  6233.  
  6234.     if(mn_get_total(ps->msgmap) > 0L){
  6235.         ps->redrawer = att_cur_drawer;
  6236.         att_cur_drawer();
  6237.     }
  6238.  
  6239.     if(mn_get_total(ps->msgmap) > 0L
  6240.        && (ch = one_try_want_to("Attach current message to report",
  6241.                     'y','x',NO_HELP,0,1)) == 'y'){
  6242.         *pp              = mail_newbody_part();
  6243.         pb              = &((*pp)->body);
  6244.         pb->type          = TYPEMESSAGE;
  6245.         pb->id              = generate_message_id(ps);
  6246.         sprintf(tmp, "Problem Message (%ld of %ld)",
  6247.             mn_get_cur(ps->msgmap), mn_get_total(ps->msgmap));
  6248.         pb->description          = cpystr(tmp);
  6249.  
  6250.         /*---- Package each message in a storage object ----*/
  6251.         if(!(pb->contents.binary = (void *)so_get(PART_SO_TYPE, NULL,
  6252.                               EDIT_ACCESS))){
  6253.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6254.         goto bomb;
  6255.         }
  6256.  
  6257.         /* write the header */
  6258.         if((p = mail_fetchheader(ps->mail_stream, msgno)) && *p)
  6259.           so_puts((STORE_S *)pb->contents.binary, p);
  6260.         else
  6261.           goto bomb;
  6262.  
  6263. #if    defined(DOS) && !defined(WIN32)
  6264.         /* write fetched text to disk */
  6265.         mail_parameters(ps->mail_stream, SET_GETS, (void *)dos_gets);
  6266.         append_file = (FILE *)so_text((STORE_S *)pb->contents.binary);
  6267.  
  6268.         /* HACK!  See mailview.c:format_message for details... */
  6269.         ps->mail_stream->text = NULL;
  6270.         /* write the body */
  6271.         if(!mail_fetchtext(ps->mail_stream, msgno))
  6272.           goto bomb;
  6273.  
  6274.         pb->size.bytes = ftell(append_file);
  6275.         /* next time body may stay in core */
  6276.         mail_parameters(ps->mail_stream, SET_GETS, (void *)NULL);
  6277.         append_file   = NULL;
  6278.         mail_gc(ps->mail_stream, GC_TEXTS);
  6279.         so_release((STORE_S *)pb->contents.binary);
  6280. #else
  6281.         pb->size.bytes = strlen(p);
  6282.         so_puts((STORE_S *)pb->contents.binary, "\015\012");
  6283.         if((p = mail_fetchtext(ps->mail_stream, msgno)) &&  *p)
  6284.           so_puts((STORE_S *)pb->contents.binary, p);
  6285.         else
  6286.           goto bomb;
  6287.  
  6288.         pb->size.bytes += strlen(p);
  6289. #endif
  6290.     }
  6291.     else if(ch == 'x'){
  6292.         q_status_message(SM_ORDER, 0, 3, "Bug report cancelled.");
  6293.         goto bomb;
  6294.     }
  6295.     }
  6296.  
  6297.     pine_send(outgoing, &body, composer_title, NULL, &fake_reply, NULL, NULL,
  6298.           NULL, NULL, 0);
  6299.  
  6300.   bomb:
  6301.     ps->mangled_screen = 1;
  6302.     if(outgoing)
  6303.       mail_free_envelope(&outgoing);
  6304.     if(body)
  6305.       pine_free_body(&body);
  6306.  
  6307.     return(10);
  6308. }
  6309.  
  6310.  
  6311. static char att_cur_msg[] = "\
  6312.          Reporting a bug...\n\
  6313. \n\
  6314.   If you think that the \"current\" message may be related to the bug you\n\
  6315.   are reporting you may include it as an attachment.  If you want to\n\
  6316.   include a message but you aren't sure if it is the current message,\n\
  6317.   cancel this bug report, go to the folder index, place the cursor on\n\
  6318.   the message you wish to include, then return to the main menu and run\n\
  6319.   the bug report command again.  Answer \"Y\" when asked the question\n\
  6320.   \"Attach current message to report?\"\n\
  6321. \n\
  6322.   This bug report will also automatically include your pine\n\
  6323.   configuration file, which is helpful when investigating the problem.";
  6324.  
  6325. /*
  6326.  * Used by gripe_tool.
  6327.  */
  6328. void
  6329. att_cur_drawer()
  6330. {
  6331.     int           i, dline, j;
  6332.     char       buf[256];
  6333.  
  6334.     /* blat helpful message to screen */
  6335.     ClearBody();
  6336.     j = 0;
  6337.     for(dline = 2;
  6338.     dline < ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global);
  6339.     dline++){
  6340.     for(i = 0; i < 256 && att_cur_msg[j] && att_cur_msg[j] != '\n'; i++)
  6341.       buf[i] = att_cur_msg[j++];
  6342.  
  6343.     buf[i] = '\0';
  6344.     if(att_cur_msg[j])
  6345.       j++;
  6346.     else if(!i)
  6347.       break;
  6348.  
  6349.         PutLine0(dline, 1, buf);
  6350.     }
  6351. }
  6352.